Codeforces Round 827 (Div. 4)题解ABCDEFG
题意:给定一个长为 n (2≤n≤2×105) 的序列 a (1≤ai≤1000),求 gcd(ai,aj)=1max{i+j}。想要确定 bi,只需要枚举还没有选择的 aj,使得 bi=bi−1oraj 最大 即可。求每次操作之后,是否可以重新排列 s 和 t 的字符,使 s 字典序比 t 小,如果可以,则输出“YES”,否则输出“NO”。q 次询问,对于每一个 ki (1≤
题意:给定 0≤a,b,c≤20,判定其中是否有一个数等于另两数之和,若是输出 YES,否则输出 NO。
思路:模拟
// Code Start Here
int t;
cin >> t;
while(t--){
int a , b , c;
cin >> a >> b >> c;
if((a == b + c) ||(b == a + c) ||(c == a + b))cout <<"Yes\n";
else cout <<"No\n";
}
题意:给定一个长为 n 的序列 a,判断你是否能通过重排的方式使序列严格递增。
严格递增:形式上的,有 a1<a2<⋯<an。
思路:严格单增的条件是没有重复的,模拟即可
// Code Start Here
int t;
cin >>t;
while(t--){
int n;
cin >> n;
vector<int> a(n);
for(int i = 0;i<n;i++)cin >>a[i];
map<int,int>mp;
for(int i = 0;i<n;i++)mp[a[i]]++;
bool f = true;
for(auto [k,v] : mp){
if(v > 1)f = false;
}
if(f)cout <<"Yes\n";
else cout <<"No\n";
}
题意:8×8 的染色地图,初始是白色,给你染完色的地图,. 代表白色,R 代表红色,B 代表蓝色。
其中染红色的策略必定是涂一行,染蓝色的策略必定是涂一列。颜色会覆盖。
求最后涂的颜色是什么,R代表红,B 代表蓝。
思路:非红即蓝,只要行全红一定是红 否则是蓝
// Code Start Here
int t;
cin >> t;
while(t--){
vector<string> v(8);
for(int i = 0;i<8;i++)cin >> v[i];
bool f = false;
for(string s : v){
if (s == "RRRRRRRR") f = true;
}
if(f)cout <<'R' << endl;
else cout <<'B' << endl;
}
题意:给定一个长为 n (2≤n≤2×105) 的序列 a (1≤ai≤1000),求 gcd(ai,aj)=1max{i+j}。换句话说,求 i+j 的最大值,其中 i,j 满足 ai 和 aj 互质。
思路:观察到序列长度为1e5但是数据范围很小,想到可以离散化,由于题目要求求最大max(ai,aj),若对于同一个ai,aj出现多次,显然选择最后出现的位置最优。离散化之后模拟即可,数据范围1010 ^ 2可以接受
// Code Start Here
int t;
cin >> t;
while(t--){
int n;
cin >> n;
vector<int> a(N);
for(int i = 1;i<=n;i++)cin >>a[i] ;
vector<int> vis(M,-1);
for(int i = 1;i<=n;i++)vis[a[i]] = max(vis[a[i]],i);
vector<int> v;
for(int i = 1;i<M;i++)if(vis[i]!=-1)v.push_back(vis[i]);
int ans = -1;
for(int i = 0;i<int(v.size());i++){
for(int j = i;j<int(v.size());j++){
if(gcd(a[v[i]],a[v[j]]) == 1){
ans = max(ans,v[i] + v[j]);
}
}
}
cout << ans <<endl;
}
题意:
有 n 阶楼梯,当前楼梯与上一阶楼梯的高度差为 ai(a1 就是第一节阶梯的高度)。
q 次询问,对于每一个 ki (1≤i≤q),若 Timur 一步能提高 ki 的高度,求出他能到达的最高高度。
思路:
观察到楼梯的位置高度单调递增,显然可以用前缀和记录。其次思考到如果遇到一个跨不上去的,那么这个后面的也跨不上去,要跨上楼梯所需要的步长在优化后也具有单增的性质,前缀和+二分即可
// Code Start Here
int t;
cin >> t;
while(t--){
memset(s , 0 , sizeof s);
int n , q;
cin >> n >> q;
for(int i = 1;i<=n;i++){
cin >> a[i];
s[i] = s[i-1] + a[i];
a[i] = max(a[i-1] ,a[i]);
}
while(q--){
int x;
cin >> x;
cout << s[(upper_bound(a+1,a+1+n,x)-a-1)] << " ";
}
cout << endl;
}
return 0;
题意:你有两个字符串 s 和 t,它们初始都为 a,你会对字符串进行 q 次操作两种类型的操作:
1kx ,在 s 末尾添加字符串 k 恰好 x 次
2kx ,在 t 末尾添加字符串 k 恰好 x 次
求每次操作之后,是否可以重新排列 s 和 t 的字符,使 s 字典序比 t 小,如果可以,则输出“YES”,否则输出“NO”。
思路:如果 t 中有一个字符不是 a,那么只要把那个字符移到第一位,就可以满足 s 的字典序小于 t,而如果两个字符串中都只有 a就比较两个s的大小即可
// Code Start Here
int t;
cin >> t;
while(t--){
int val_a=0,val_b=0,flag1=0,flag2=0;
int q;
cin >> q;
while(q--){
int op , x;
string a;
cin >> op >> x >> a;
if(op==1){
for(int i=0;i<int(a.size());i++) if(a[i]!='a') flag2=1;
val_a+=x*int(a.size());
}
else{
for(int i=0;i<int(a.size());i++) if(a[i]!='a') flag1=1;
val_b+=x*int(a.size());
}
if(!flag1&&flag2) cout<<"No"<<endl;
else if(flag1) cout<<"Yes"<<endl;
else if(val_a<val_b) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
题意:我们定义前缀或的意思是 ori=ori−1orai。重排数组 a,使得它的前缀或数组的字典序最大。
思路:为了保证字典序最大,b1 一定是 a 中最大的数,然后依次确定 b2,b3,…bn。想要确定 bi,只需要枚举还没有选择的 aj,使得 bi=bi−1oraj 最大 即可。
// Code Start Here
int t;cin >> t;while(t--){
const int N = 2e5+10;
int n;
cin >> n;
vector<int> a(N);
vector<bool> vis(N,false);
for(int i = 1;i<=n;i++)cin >> a[i];
int now = 0;
for(int i = 1;i<=min(n,60LL);i++){
int anow = -1;
int temp;
for(int j = 1;j<=n;j++){
if(!vis[j] && anow <(now | a[j])){
anow = (now | a[j]);
temp = j;
}
}
vis[temp] = true;
now |= a[temp];
cout << a[temp] <<" ";
}
for(int i = 1;i<=n;i++){
if(!vis[i])cout << a[i] <<" ";
}
cout <<endl;
}
更多推荐



所有评论(0)