Codeforces Global Round 10(A->D(环问题))
A:http://codeforces.com/contest/1392/problem/A
题意:
相邻的不同数可以相加合成一个数,问最后最少会剩下几个数
解析:
随便写一下,就会发现,只要数组中只要存在不同数,最后就一定能合成一个数。
所以,全相等,输出n,否则1
#include<bits/stdc++.h> #include<map> #include<iostream> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int maxn=2e5+20; //const ll inf=0x3f3f3f3f3f3f3f3f; ll a[maxn]; int main() { int t; cin>>t; while(t--) { int n; cin>>n; int ok=0; for(int i=1;i<=n;i++) cin>>a[i]; if(n==1) { cout<<"1"<<endl;continue; } for(int i=2;i<=n;i++) { if(a[i]!=a[i-1]) { ok=1;break; } } if(ok) cout<<"1"<<endl; else cout<<n<<endl; } }
B:http://codeforces.com/contest/1392/problem/B
题意:
每次操作让当前数组的最大值去减数组的每一个数,求第k次操作的数组
解析:
列了一下,发现,k=1,变一次,k=2,变两次,k=3,变三次
对于k>1,奇数变三次,偶数变两次
模拟一下即可。
关于最大值的选择,不少人赛后被hack掉,所以建议最大值直接设为a[1]妥当。
#include<bits/stdc++.h> #include<map> #include<iostream> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int maxn=2e5+20; //const ll inf=0x3f3f3f3f3f3f3f3f; ll a[maxn]; int main() { int t; cin>>t; while(t--) { int n; ll k; cin>>n>>k; ll maxx; cin>>a[1]; maxx=a[1]; for(int i=2;i<=n;i++) cin>>a[i],maxx=max(a[i],maxx); if(k==1) { for(int i=1;i<=n;i++) { cout<<maxx-a[i]<<' '; } cout<<endl;continue; } ll maxx2=maxx-a[1]; a[1]=maxx-a[1]; for(int i=2;i<=n;i++) { a[i]=maxx-a[i]; maxx2=max(maxx2,a[i]); } ll maxx3=maxx2-a[1]; a[1]=maxx2-a[1]; for(int i=2;i<=n;i++) { a[i]=maxx2-a[i]; maxx3=max(maxx3,a[i]); } if(k%2==0) { for(int i=1;i<=n;i++) cout<<a[i]<<" "; cout<<endl;continue; } ll maxx4=maxx3-a[1]; a[1]=maxx3-a[1]; for(int i=2;i<=n;i++) { a[i]=maxx3-a[i]; maxx3=max(maxx3,a[i]); } for(int i=1;i<=n;i++) cout<<a[i]<<" "; cout<<endl; } }
C:http://codeforces.com/contest/1392/problem/C
题意:
给出序列,操作:对不递减的区间里的每一个数都加1,将整个序列变成非递减序列所需要的最少操作数。
解析:
本来分析复杂了,涉及到区间问题。但是把序列倒着遍历,思路就很清晰了。
ai<ai-1,把ai增加到和ai-1相同。
以后再遇到这种情况,ai后集体跟着加1即可。
#include<bits/stdc++.h> #include<map> #include<iostream> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int maxn=2e5+20; //const ll inf=0x3f3f3f3f3f3f3f3f; ll a[maxn]; int main() { int t; cin>>t; while(t--) { int n; cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; ll ans=0; for(int i=n;i>1;i--) { if(a[i]<a[i-1]) ans+=(a[i-1]-a[i]); } cout<<ans<<endl; } }
D:http://codeforces.com/contest/1392/problem/D
题意:
n个人围成一圈。字符串表示每个人攻击的是左边的人还是右边的人。
合法情况:
如果一个人被攻击一次,那么他要反击那个人
如果一个人被攻击0或两次,他可以对左右任选一个攻击。
将游戏变成合法,最少需要纠正几个人?
解析:
先把环变成链
1:全L或全R的情况,
RRR->RRL,RRRR->RRLL,RRRRR->RRLRL , RRRRRR->RRLRRL
有结论,此时结果为:n/3+(n%3>0)
2:L和R均有
借助1的结论,固定到第一个a[k]!=a[0],往后记录连续和a[k]相等的,cnt++
a[i]!=a[k],记录总数sum+=cnt/3,cnt重置,k改变
注意对于cnt<3,是不需要改的,这部分肯定是符合条件的。
#include<bits/stdc++.h> #include<map> #include<iostream> #include<cstring> #include<cmath> using namespace std; typedef long long ll; const int maxn=2e5+20; char s[3*maxn]; //const ll inf=0x3f3f3f3f3f3f3f3f; ll a[maxn]; int main() { int t; cin>>t; while(t--) { // string s; int n; cin>>n; scanf("%s",s); for(int i=0;i<n;i++) s[i+n]=s[i]; int k=-1; for(int i=1;i<n;i++) { if(s[i]!=s[0]) { k=i; break; } } if(k==-1) { cout<<n/3+(n%3>0)<<endl; continue; } int id=k; ll sum=0; int cnt=0; for(int i=k;i<n+k;i++) { if(s[i]==s[id]) cnt++; else { sum+=cnt/3; cnt=1; id=i; } } sum+=cnt/3; cout<<sum<<endl; } }