Codeforces Round #610 (Div. 2) A-E简要题解

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 }

 

 
 
posted @ 2020-01-01 21:30  AaronChang  阅读(214)  评论(0编辑  收藏  举报