Codeforces Round #655 (Div. 2)【ABCD】(题解) 涵盖知识点:思维、前缀和
比赛链接:传送门
A - Omkar and Completion
题意: 要求构造一个长度为(n)的数组满足任意两个数相加不等于第三个数
题解: 全(1)即可
Accept Code:
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;cin>>t;
while(t--){
int n;
cin>>n;
for(int i=0;i<n;i++)cout<<"1 ";
cout<<"
";
}
return 0;
}
B - Omkar and Last Class of Math
题意: 给定(n),要求找到一组(a,b)满足(a+b=n)且(LCM(a,b))尽可能小。
题解: 要使(LCM)尽可能小,那么(GCD)就要尽可能大,从小到大枚举(n)的因子即可。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;cin>>t;
while(t--){
int n;
cin>>n;
for(int i=2;i<=sqrt(n);i++){
if(n%i==0){
cout<<n/i<<" "<<n-n/i<<"
";
goto st;
}
}
cout<<1<<" "<<n-1<<"
";
st:;
}
return 0;
}
C - Omkar and Baseball
题意: 给定一种操作可以使得某区间内所有数字任意排列,但是要满足所有数字都不能在自己原来的位置上。问多少次操作可以将原本的乱序排列变为递增排列。
题解: 分类讨论。原本就满足条件:0;原本全乱序:1;原本除前缀和后缀外全乱序:1;其他情况:2.证明自行脑补一下。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int a[maxn];
int main(){
int t;cin>>t;
while(t--){
int n;
cin>>n;
int ans=0;
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==i)ans++;
}
if(ans==n){
cout<<0<<"
";
continue;
}
for(int i=1;i<=n;i++){
if(a[i]==i)ans--;
else break;
}
for(int i=n;i>=1;i--){
if(a[i]==i)ans--;
else break;
}
if(ans==0)cout<<1<<"
";
else cout<<2<<"
";
}
return 0;
}
D - Omkar and Circle
题意: (n)个数字组成一个环,每次操作选择一个数并将其变为两个相邻数字的和并删除相邻数字。通过若干次操作最后会只剩下一个数字。(因为(n)为奇数)。问这个数字最大是多少
题解: 在纸上自己操作几次之后,就会发现在确定断点以后,相邻位置的数字无论怎么变化一定会合并,只是顺序不同。所以按照奇偶性计算一下前缀和并两倍延长一下取区间最大值即可。
UPD: 图片仅作示意,思路推导过程。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
ll a[maxn<<1],sum[maxn<<1];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i],a[i+n]=a[i];
sum[1]=a[1];
for(int i=2;i<=n*2;i++)sum[i]=sum[i-2]+a[i];
ll ans=0;
for(int i=n+1;i<=2*n;i++)ans=max(ans,sum[i]-sum[i-n-1]);
cout<<ans<<"
";
return 0;
}