Codeforces Global Round 10
Codeforces Global Round 10
A. Omkar and Password
可以任意合并数组相邻不相等的元素,最终数组所有元素都相同,求最短长度。
原数组元素全相同答案为n,反之为1.
B. Omkar and Infinity Clock
每次找出数组最大值,a[i]=mx-a[i],求k(1e18)次后的数组。
模拟了一下发现有规律,根据k的奇偶判断一下就好了。
分析:第一次操作之后,最大值的位置就是原来最小值的位置,之后就是最大最小值不断交换的过程。
if(k&1) { for(int i=0;i<n;i++) a[i]=mx-a[i]; } else { for(int i=0;i<n;i++) a[i] -= mi; }
C. Omkar and Waterslide
给定一个序列,每次可以在一个相同高度的子段上+1,求使其变成单调不减序列最小操作次数。
答案就是下降的差值之和,举个例子,5 1 2 3
,如果1加到了5那么23肯定也到5了。
for(int i=1;i<n;i++) { if(a[i]<a[i-1]) sum+=a[i-1]-a[i]; }
D. Omkar and Bed Wars
给定包含RL
的字符串,分别代表当前位置上的人向右方/左方发起攻击。求最小的更改次数,使其满足:如果当前位置受到单侧攻击则向其反击,受到双侧攻击则向任意一个方向反击。所有人围成的是一个环。
观察一下,合法字符串包括RL
RLL
RLLR
,只要连续出现的次数不超过三次就是合法的。全R或全L需要特判。
#include <bits/stdc++.h> using namespace std; typedef long long ll; int t,n,len,ans,cnt; string s; int main() { scanf("%d",&t); while(t--) { vector<int> v; scanf("%d",&n); cin >> s; cnt=1; ans=0; for(int i=1;i<n;i++) { if(s[i]==s[i-1]) cnt++; else v.push_back(cnt), cnt=1; } if(cnt) v.push_back(cnt); len = v.size(); if(len==1) { printf("%d\n", (n+2)/3); continue; } if(s[0]==s[s.length()-1]) v[0]+=v[--len]; for(int i=0;i<len;i++) ans+=v[i]/3; printf("%d\n",ans); } }
E. Omkar and Duck
这是一道交互题。
给定n,要求输出n×n的矩阵,每个值分别代表点 (i,j) 的权值,系统会给出q个合法权值w,每次要求从左上角走到右下角,只能向右或下走,总权值恰好为w且路径唯一。
往二进制的角度思考
如果需要恰好为w:(对角线相等)
加上路径唯一的条件
那么其实就是在每一步判断下一步对应的二进制位上是否有1。
注意:输出后要加上fflush(stdout)
(scanf星人表示-_-||),C++ cout<<endl;
可以自动清空缓存区。
#include <bits/stdc++.h> using namespace std; typedef long long ll; int n,q,x,y; ll t; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i&1) printf("0 "); else printf("%lld ",1LL<<(i+j)); } printf("\n"); } fflush(stdout); scanf("%d",&q); while(q--) { scanf("%lld",&t); x = y = 1; // printf("%d %d\n",x,y); cout << x << " " << y << endl; for(int i=1;i<=2*n-2;i++) { if(x&1) { if(t&(1LL<<(x+y+1))) x++; else y++; } else { if(t&(1LL<<(x+y+1))) y++; else x++; } cout << x << " " << y << endl; // printf("%d %d\n",x,y); } } }
F. Omkar and Landslide
给定数组h,如果h[i]+2<=h[i+1],则h[i]--,h[i+1]++,一直重复到不能进行操作为止,求最终的数组。
打表找规律,先构造等差数列剩下加1即可。
打表代码
#include <bits/stdc++.h> #define random(a,b) ((a)+rand()%((b)-(a)+1)) using namespace std; int n,cnt; int a[20]; void print(int n) { for(int i=1;i<=n;i++) { printf("%d ",a[i]); } printf("\n"); } void init(int n) { srand((unsigned)time(NULL)); int sum=0; for(int i=1;i<=n;i++) { a[i]=random(a[i-1]+1,a[i-1]+8); sum+=a[i]; } print(n); printf("Sum=%d, Sum/n=%.2f\n",sum,1.0*sum/n); } int fun(int n) { for(int i=1;i<n;i++) { while(a[i]+2<=a[i+1]) { a[i]++;a[i+1]--; } } } int check(int n) { for(int i=1;i<n;i++) { if(a[i]+2<=a[i+1]) { return 1; } } return 0; } int main() { n=6; init(n); while(check(n)) fun(n); print(n); }
解题代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6 + 5; ll n,sum; ll a[maxn], ans[maxn]; int main() { scanf("%lld",&n); for(int i=0;i<n;i++) scanf("%lld",&a[i]), sum+=a[i]; ans[0]=(2*sum-n*n)/(2*n); sum-=ans[0]; for(int i=1;i<n;i++) { ans[i]=ans[i-1]+1; sum-=ans[i]; } int j=0; while(sum>0) { sum--; ans[(j++)%n]++; } for(int i=0;i<n;i++) { printf("%lld ",ans[i]); } }