CF练习记录

2018/5/6
Codeforces Round #478 (Div. 2) C
http://codeforces.com/contest/975/problem/C
Valhalla Siege

题意:n的士兵,每个士兵有一些生命值,有q次询问,每次询问从前向后造成ki点贯穿伤害(生命值归零的士兵死去,后续士兵承受溢出伤害),问每次询问有几个士兵还活着。当所有士兵死去时,不继续造成溢出伤害并且所有士兵复活。

思路:二分搜索,对士兵生命值求前缀和,每次询问造成的伤害累计,记为s,用upper_bound来寻找前缀和中大于s的第一个人的位置i,n-i就是剩下的人数,如果剩下的人数为0(死完了),就全部复活,s清0。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int MAX_N = 200000 + 8;
 5 ll x[MAX_N];
 6 ll sum[MAX_N];
 7 int main()
 8 {
 9     int i,n,q;
10     cin >> n >> q;
11 
12     memset(sum,0x3f,sizeof(sum));
13     for(i=0;i<n;i++){
14         cin >> x[i];
15         if(i)
16             sum[i]=sum[i-1]+x[i];
17         else
18             sum[i]=x[i];
19     }
20     ll s=0,tmp;
21     for(i=0;i<q;i++){
22         cin >> tmp;
23         s+=tmp;
24         int index=upper_bound(sum,sum+MAX_N,s)-sum;
25         if(n-index<=0)
26         {
27             s=0;
28             index=0;
29         }
30         cout << n-index << "\n";
31     }
32     return 0;
33 }
View Code

 Codeforces Round #476 (Div. 2) 

http://codeforces.com/contest/965/problem/C

D<=1000,因此可以简单枚举,每次最大一定是n/((i-1)*k+1) * i,但是有很多情况需要特判排除。

题解,https://www.cnblogs.com/AWCXV/p/8949119.html

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 
 6 int main()
 7 {
 8     ios_base::sync_with_stdio(false);
 9     cin.tie(0);
10     ll  n,k,M,D;
11     cin  >> n >> k >> M >> D;
12     ll ans=M;
13     for(ll i=2;i<=D;i++)
14     {
15         ll x=n/((i-1)*k+1);
16 
17         if(x==0)break;
18         if(x>M)x=M;
19         if ((n/(k*x)+((n%(k*x)>=x?1:0)))!=i) continue;
20         ans=max(ans, x*i);
21     }
22     cout << ans << "\n";
23 
24     return 0;
25 }
View Code

 

 2018/5/17

http://codeforces.com/contest/984/problem/C

题意:给出p,q,b,求b进制下p/q是否为无穷小数。

思路:先用gcd将p/q化为真分数,再对于q和b:由于p和q互质,之后的过程就与p无关了。

由于是b进制,每进一位就相当于原小数*b,那么这个过程中就相当于q/gcd(q,b)。持续到q和gcd(q,b)其中一个为1即可。

一开始直接用快速幂……超时,%lld CF不能用CE。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 
 6 ll gcd(ll x,ll y){
 7     return y==0?x:gcd(y,x%y);
 8 }
 9 
10 
11 int main()
12 {
13     ios::sync_with_stdio(false);
14     cin.tie(0);
15     ll p,q,b;
16     int n;
17     cin >> n;
18     while(n--){
19         cin >> p >> q >>b;
20         ll x=p/gcd(p,q);
21         ll y=q/gcd(p,q);
22         ll cheek=gcd(y,b);
23         while(y!=1&&cheek!=1){
24             while(y%cheek==0)y/=cheek;
25             cheek=gcd(b,y);
26         }
27         if(y==1)
28             cout << "Finite\n";
29         else
30             cout << "Infinite\n";
31     }
32 }
View Code

 

 

2018/5/22

http://codeforces.com/contest/982

B

【题意】:

就是说有一辆公交车,有n排;

接下来n个数据代表n排的权值(每排只能坐2个人);

然后接下来又2*n的数据

代表要坐入这辆公交车的人的类型。

1代表外向型,0代表内向型。

外向型:优先选择旁边有人的且权值最大的位置,如果没有的话,选择权值最大的位置。

内向型:优先选择没人的位置且权值最小的位置。

【思路】:

首先定义座位的属性:

状态:0代表旁边没人,1代表旁边有人。

第几排

权值

维护两个优先队列

优先队列0,用于维护旁边没人的座位,权值最小的排在最前面。

优先队列1,用于维护旁边有人的座位,权值最大的排在最前面。

一开始座位都没人,都存入队列0.

每次操作,从相应队列找最前面的位置,若队列0中找到座位,则将座位的状态改变存入队列1.

之后删除相应队列中的该座位。

输出即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 struct node{
 6     int state;
 7     int row;
 8     int pow;
 9     node(int s,int r,int p):state(s),row(r),pow(p){};
10     node(){}
11 };
12 
13 struct rule0{
14     bool operator()(const node &a,const node &b){
15         return a.pow<b.pow||a.pow==b.pow&&a.row<b.row;
16     }
17 };
18 
19 struct rule1{
20     bool operator()(const node &a,const node &b){
21         return a.pow>b.pow||a.pow==b.pow&&a.row<b.row;
22     }
23 };
24 
25 int main(){
26     set<node,rule1> st1;
27     set<node,rule0> st0;
28     set<node,rule0>::iterator it0;
29     set<node,rule1>::iterator it1;
30 
31     int n;
32     cin >> n;
33     int pow;
34     for(int i=0;i<n;i++){
35         cin >> pow;
36         node tmp(0,i+1,pow);
37         st0.insert(tmp);
38     }
39     string people;
40     cin >> people;
41     for(int i=0;people[i];i++){
42         if(people[i]=='0'){
43             it0=st0.begin();
44             if(it0!=st0.end()){
45                 node tmp=*it0;
46                 st0.erase(it0);
47                 tmp.state++;
48                 st1.insert(tmp);
49                 printf("%d%c",tmp.row,i==2*n-1?'\n':' ');
50                 continue;
51             }
52             else{
53                 it1=st1.begin();
54                 node tmp=*it1;
55                 st1.erase(it1);
56                 printf("%d%c",tmp.row,i==2*n-1?'\n':' ');
57                 continue;
58             }
59 
60         }
61         else {
62             it1=st1.begin();
63             if(it1==st1.end()){
64                 it0=st0.begin();
65                 node tmp=*it0;
66                 st0.erase(it0);
67                 tmp.state++;
68                 st1.insert(tmp);
69                 printf("%d%c",tmp.row,i==2*n-1?'\n':' ');
70                 continue;
71             }
72             else{
73                 node tmp=*it1;
74                 st1.erase(it1);
75                 printf("%d%c",tmp.row,i==2*n-1?'\n':' ');
76                 continue;
77             }
78         }
79     }
80 }
View Code

C

题意:https://www.cnblogs.com/kickit/p/9054233.html

给出一棵树,问最多去掉多少条边之后,剩下的连通分量的size都是偶数。

思路:

如果本来就是奇数个点,那么无论去掉多少条边都不可能成立的。

如果是偶数个点,就进行一次dfs,假设一个点的父亲是u,儿子是v,那么可以去掉(u,v)的条件就是v及其子树有偶数个点,任何一条这样的边都是可以去掉的。

所以一边dfs,一边统计答案就可以了。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int n;
 5 vector<int> v[100010];
 6 int ret;
 7 int dfs(int u,int f){
 8     int ans=1;
 9     for(int i=0;i<v[u].size();i++){
10         if(v[u][i]!=f){
11             int tmp=dfs(v[u][i],u);
12             if(tmp%2==0)ret++;
13             ans+=tmp;
14         }
15     }
16     return ans;
17 }
18 
19 int main(){
20     cin >> n;
21     if(n&1){
22         cout << -1 <<endl;
23         return 0;
24     }
25 
26     int x,y;
27     int start=-1;
28     for(int i=1;i<n;i++){
29         cin >>x >>y;
30         v[x].push_back(y);
31         v[y].push_back(x);
32     }
33     dfs(1,-1);
34     cout << ret <<endl;
35 }
View Code

479 C

阴险的陷阱题……

题意:

给一些数,范围从1到1e9,问是否存在一个数,使得正好有k个数小于等于这个数

思路:

很容易想到排序,前k个数一定是选入的,只要判断第k+1个数是否等于第k个数即可。

然而……WA了

问题在于k可以取0.

范围是从1开始的,所以还要判断这种情况下最小的数是否大于1,以上。 

codeforces.com/contest/977

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 
 5 int main(){
 6     int x[200010];
 7     int n,k;
 8     while(cin >> n >> k){
 9         memset(x,0x3f,sizeof(x));
10         for(int i=0;i<n;i++){
11             cin >> x[i];
12         }
13         sort(x,x+n);
14         if(k==0){
15             if(x[0]>1)
16                 printf("1\n");
17             else
18                 printf("-1\n");
19             continue;
20         }
21         else if(x[k]!=x[k-1])
22             printf("%d\n",x[k-1]);
23         else
24             printf("-1\n");
25 
26     }
27 }
View Code

 

Educational Codeforces Round 42

C. Make a Square

http://codeforces.com/contest/962/problem/C

题意:给一个无前导零的数,你可以删除任意多的数字,使得它成为一个无前导零的平方数……吗?若可以,输出最少操作数,若不可以,输出-1.

思路:

混乱……

开玩笑的,今天状态太差了,这么一道破水题卡了我一个小时,我还看题解了……

总之,题目很简单,暴力枚举,数据范围2e9,枚举所有可能情况最多也就1024种情况,每种情况判断是否无前导零、是否为平方数(开根号平方等于本身)即可。

一开始zz想用ac自动机被卡、情况0未考虑被卡、前导零未考虑被卡……

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <string.h>
 4 #include <string>
 5 #include <iostream>
 6 #include <math.h>
 7 using namespace std;
 8 
 9 int main()
10 {
11     int i,j,tmp;
12     string t;
13     cin >> t;
14     int flag=0,ans=0;
15     for(i=1;i<(1<<t.size());i++){
16         tmp=i;
17         int s=0;
18         j=0;
19         int num=0;
20         while(tmp>0){
21             if( !(!s&&t[j]=='0') && (tmp&1) ){
22                 s=s*10+t[j]-'0';
23                 num++;
24             }
25             j++;
26             tmp>>=1;
27         }
28         if(s&&(int)sqrt(s)*(int)sqrt(s)==s ){
29             ans=max(ans,num);
30             flag=1;
31         }
32     }
33     if(!flag){
34         printf("-1\n");
35     }
36     else
37         printf("%d\n",t.size()-ans);
38     return 0;
39 }
View Code

 

 

5.24

http://codeforces.com/contest/985

越写越觉得自己是zz……

1.水题暴力即可,没考虑排序……

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 int abs(int x){
 5     return x > 0 ? x : -x;
 6 }
 7 
 8 int main()
 9 {
10     int n;
11     int x[110];
12     cin >> n ;
13     for(int i=0;2*i<n;i++){
14         cin >> x[i];
15     }
16     sort(x,x+n/2);
17     int a=0,b=0;
18     for(int i=0;2*i<n;i++){
19         a+=abs(2*i+2-x[i]);
20     }
21     for(int i=0;2*i<n;i++){
22         b+=abs(2*i+1-x[i]);
23     }
24     printf("%d\n",min(a,b));
25     return 0;
26 }
View Code

2.水题

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 
 5 int x[2010]={0};
 6 string a[2010];
 7 int main()
 8 {
 9     int n,m,flag,yes=0;
10     cin >> n  >> m;
11     for(int i=0;i<n;i++){
12         cin >> a[i];
13         for(int j=0;a[i][j];j++){
14             if(a[i][j]=='1')
15                 x[j]++;
16         }
17     }
18     for(int i=0;i<n;i++){
19         flag=1;
20         for(int j=0;a[i][j];j++){
21             if(a[i][j]=='1'&&x[j]<2){
22                 flag=0;
23             }
24         }
25         if(flag){
26             yes=1;
27             printf("YES\n");
28             break;
29         }
30     }
31     if(!yes){
32         printf("NO\n");
33     }
34     return 0;
35 }
View Code

3.贪心

确定能选的范围,之后每次选能选到的最大的。

爆int,用long long

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 typedef long long ll;
 5 ll x[100010];
 6 int main()
 7 {
 8     int n,k,l;
 9     cin >> n >> k >> l;
10     for(int i=0;i<n*k;i++){
11         cin >> x[i];
12     }
13     sort(x,x+n*k);
14     int index=upper_bound(x,x+n*k,x[0]+l)-x;
15 //    cout << index <<endl;
16     if(index<n){
17         printf("0\n");
18         return 0;
19     }
20     ll sum=0;
21 //    for(int i=0;i<n*k;i++)
22 //        printf("%d\t",x[i]);
23 
24     for(int i=0;n&&i<index;){
25         sum+=x[i];
26         i+=min(k,max(index-i-n+1,1));
27         n--;
28 //        printf("index-i-n+1:%d\n",index-i-n+1);
29 //        printf("i:%d\n",i);
30     }
31     cout << sum << endl;
32     return 0;
33 }
View Code

 

5.25

1.水题,注意n==0的情况即可

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     long long n;
 8     cin >> n;
 9     if(!n){
10         cout << 0 << endl;
11         return 0;
12     }
13     n++;
14     
15     if(n%2==0)
16         cout <<n/2 <<endl;
17     else
18         cout << n << endl;
19     return 0;
20 }
View Code

2.贪心,注意特殊情况,全部相同字符情况n==1时减少一位

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     string a[3];
 8     int num;
 9     cin >> num >> a[0] >> a[1] >> a[2];
10     int ch[3][300]={0};
11     for(int j=0;j<3;j++){
12 
13         for(int i=0;a[j][i];i++){
14             ch[j][ a[j][i] ]++;
15             ch[j][0]=max(ch[j][0],ch[j][a[j][i]]);
16         }
17         if(num==1&&ch[j][0]==(int)a[j].size()){
18             ch[j][0]--;
19             continue;
20         }
21         ch[j][0]=min(ch[j][0]+num,(int)a[j].size());
22 
23     }
24     int maxn=max(max(ch[0][0],ch[1][0]),ch[2][0]);
25     if(maxn==ch[0][0]&&maxn==ch[1][0]||
26        maxn==ch[0][0]&&maxn==ch[2][0]||
27        maxn==ch[2][0]&&maxn==ch[1][0])
28         cout << "Draw\n";
29     else if(maxn==ch[0][0])
30         cout << "Kuro\n";
31     else if(maxn==ch[1][0])
32         cout << "Shiro\n";
33     else if(maxn==ch[2][0])
34         cout << "Katie\n";
35 
36     return 0;
37 }
View Code

 

转载于:https://www.cnblogs.com/bestefforts/p/8997640.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值