contest链接: https://codeforces.com/contest/1282
A. Temporarily unavailable
题意: 给一个区间L,R通有网络,有个点x,在x+r和x-r范围内,没有网络,问在这个区间上有网络的长度范围
思路:枚举区间覆盖情况,注意细节
AC代码:
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 using namespace std; 8 typedef long long ll; 9 ll mod = 1e9+7; 10 int main(){ 11 int q;cin>>q; 12 while(q--){ 13 ll a,b,c,d; 14 cin>>a>>b>>c>>d; 15 if(a>b) swap(a,b); 16 ll l = c-d,r = c+d; 17 if(b<=l) {cout<<b-a<<endl;continue;} 18 if(a>=r) {cout<<b-a<<endl;continue;} 19 if(l<=a&&r>=b) {cout<<0<<endl;continue; } 20 if(l>=a && r<=b){ 21 cout<<b-a-2*d<<endl; 22 continue; 23 } 24 if(l<=a&&r>=a&&r<=b){ 25 cout<<b-r<<endl; 26 continue; 27 } 28 if(l>=a&&l<=b&&r>=b){ 29 cout<<(l-a)<<endl; 30 continue; 31 } 32 } 33 return 0; 34 }
B1.K for the Price of One (Easy Version) 略 直接搞Hard Version
B2. K for the Price of One (Hard Version)
题意: 商店买东西,商店有n个物品,每个物品有自己的价格,商店有个优惠活动,当你买恰好k个东西时可以只为其中最贵的那个付款,求有限的钱中买到的最多的物品数量,你可以多次使用优惠。
思路:把所有商品的价格排序从小到大一遍,设第i个物品的价格是a[i],Sum[i]表示购买前i个物品花费的钱,作为前缀和。可以发现当你买了当第i个物品时,那么只需要支付Sum[i-k] + a [i] 即可,因为你买了当前的物品,可以赠送k-1个,那直接贪心着把小于等于当前这个物品价格的前K-1个物品直接赠送了,只需要支付a[i]费用,再支付一下sum[i-k]即可,维护整个过程sum[i] = sum[i-k] + a[i]即可。
AC代码:
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 using namespace std; 8 typedef long long ll; 9 ll mod = 1e9+7; 10 const int maxn = 2e5+10; 11 int main(){ 12 int q;cin>>q; 13 while(q--){ 14 ll n,p,k;cin>>n>>p>>k; 15 ll a[maxn]; 16 a[0] = 0; 17 for(int i = 1;i<=n;i++) cin>>a[i]; 18 sort(a+1,a+n+1); 19 ll ans = 0; 20 // 2 3 4 5 7 21 ll sum[n+1]; 22 memset(sum,0,sizeof(sum)); 23 sum[0] = 0; 24 sum[1] = a[1]; 25 for(int i = 2;i<=k;i++){ 26 sum[i] = sum[i-1] + a[i];//前k个物品价格必须都要算上,此时没有优惠卷 27 } 28 for(int i = k;i<=n;i++){ 29 sum[i] = sum[i-k] + a[i]; 30 } 31 for(int i = 0;i<=n;i++){ 32 if(p>=sum[i]) ans = i ; 33 } 34 cout<<ans<<endl; 35 } 36 return 0; 37 }
C. Petya and Exam
题意: 有一个人参加考试,考试只有两种题,一种是简单题,每道题耗时固定为a;另一种是困难题,每道题耗时固定为b,保证b>a。解出一道题得分都是1。考试的规则并不只是写多少题得多少分,鼓励提前交卷。假如你没有提前交卷,那么有一部分的题目会列为“必做题”,当“必做题”的题目没有全部被完成的话,这门课就算0分;否则得到与题数相同的分数,包括“必做”和“非必做”的。
题意: 题意很明显需要按题目的“必做时间”按照升序排列起来,然后贪心着做,从头开始遍历每道题目的必做时间。假如遍历到第i个题了,当前时间为T,那么如果在T-1时刻交卷,首先需要把前面必须做的所有题目做完,假设这个过程花费了Ti时间,然后剩下了T - Ti的时间,那么我们就在剩下的时间内贪心着先做尽可能多剩余的简单题,再做难题,记录此时的ans,不断遍历所有题目的必须做时间到最后,也不断的更新ans的最大值。最终的ans就是答案
AC代码:
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 using namespace std; 8 typedef long long ll; 9 ll mod = 1e9+7; 10 const int maxn = 2e5+10; 11 struct node{ 12 int dif; 13 int ti; 14 }g[maxn]; 15 bool cmp(node a,node b){ 16 if(a.ti !=b.ti ) return a.ti<b.ti ; 17 return a.dif <b.dif ; 18 } 19 int main(){ 20 int q;cin>>q; 21 while(q--){ 22 ll n,t,a,b; 23 cin>>n>>t>>a>>b; 24 ll cnta = 0,cntb = 0; 25 for(int i = 1;i<=n;i++){ 26 int Td;cin>>Td; 27 if(Td == 0) cnta++; 28 else cntb++; 29 g[i].dif = Td; 30 } 31 for(int i = 1;i<=n;i++){ 32 int T;cin>>T; 33 g[i].ti = T; 34 } 35 sort(g+1,g+n+1,cmp);//按必做时间先排序 36 g[n+1].ti = t+1; 37 ll ans = 0,c1 = 0,c2 = 0;//c1 c2统计必做题目的个数 38 for(int i = 1;i<=n+1;i++){ 39 ll cur = a*c1 + b*c2; 40 ll time = g[i].ti - 1 - cur;//必做题目花费的时间 41 if(time>=0){//如果有多余的时间,那么尽可能做更多的简单题,再做难题 42 ll ta = min(time/a,cnta-c1); 43 time-=ta*a; 44 ll tb = min(time/b,cntb-c2); 45 ans = max(ans,c1+c2+ta+tb); 46 } 47 if(g[i].dif == 0) c1++; 48 else c2++; 49 } 50 cout<<ans<<endl; 51 } 52 return 0; 53 }
D题是交互题,没见过,ACM中没见过,先略了
E.The Cake Is a Lie
题意:给的是一张平面图,是一个n边形,每次可以切一刀,切出一个三角形,最终切成n-2个三角形。题目给出所切三角形的三个顶点的编号,以及三角形的编号。问你切出的三角形顺序,以及按顺序输出原始n边形顶点的所有编号,可以逆序输出也顺序输出。
题解:有点类似拓扑排序。首先输入三角形三个点,a,b,c,统计出V[a] Xor b Xor c,同理统计V[b],V[c],这样可以保证V[i]的值只能是0 Xor 与i相连的两个点,即使三角形有共用边,多次Xor会消除公用边相连的点。根据这个性质,可以顺序输出所有点的编号。
那么三角形顺序怎么输出呢?首先发现如果一条边是被两个三角形公用的,那么可以依据这条边把两个三角形相连,这样把三角形作为一个节点从而形成了一个图,这个图结构是一颗树,我们就随便找一个叶子节点,从叶子节点开始dfs遍历一遍,输出三角形编号即可。
AC代码:
1 #include<iostream> 2 #include<vector> 3 #include<cstring> 4 #include<map> 5 #include<algorithm> 6 using namespace std; 7 const int maxn = 1e+5; 8 int v[maxn]; 9 vector<int> g[maxn]; 10 int visit[maxn]; 11 void dfs(int x){ //从叶子节点开始搜索,因为叶子节点必定代表着最靠外的三角形,它的度是1 12 visit[x] = 1; 13 for(int i = 0;i<g[x].size() ;i++){ 14 int cur = g[x][i]; 15 if(visit[cur] ==0) dfs(g[x][i]); 16 // dfs(g[x][i]); 17 } 18 cout<<x<<" "; 19 } 20 int main(){ 21 int t;cin>>t; 22 while(t--){ 23 int n; 24 cin>>n; 25 for(int i = 0;i<=maxn;i++){ 26 v[i] = 0;//初始化V数组 27 visit[i] = 0;//初始化访问数组 28 g[i].clear() ; 29 } 30 map<pair<int,int>,vector<int> > mp; 31 for(int i = 0;i<n-2;i++){ 32 int a,b,c; 33 cin>>a>>b>>c; 34 if(a>b) swap(a,b); 35 if(b>c) swap(b,c); 36 if(a>b) swap(a,b); 37 v[a]^=b,v[a]^=c;//Xor操作 38 v[b]^=a,v[b]^=c; 39 v[c]^=a,v[c]^=b; 40 mp[{a,b}].push_back(i+1);//添加一条边a,b,以及所共用的三角形i+1 41 mp[{a,c}].push_back(i+1); 42 mp[{b,c}].push_back(i+1); 43 } 44 int a,b; 45 for(auto h:mp){ 46 if(h.second.size()==1){ //随便找一条边,只共用一个三角形 47 a = h.first.first; 48 b = h.first.second; 49 // break; 50 } 51 } 52 cout<<a<<" "<<b;//输出这条边 53 for(int i = 0;i<n-2;i++){ 54 int t = a^v[b];//开始做Xor操作。具体可以用笔模拟一下这个过程,理解更清楚 55 cout<<" "<<t; 56 a = b,b = t; 57 } 58 cout<<endl; 59 for(auto h:mp){ 60 if(h.second.size() == 2){ 61 int u = h.second[0],v = h.second[1]; 62 g[u].push_back(v),g[v].push_back(u);//根据共用边以三角形为一个点建图 63 } 64 } 65 dfs(1); 66 cout<<endl; 67 } 68 return 0; 69 }