Codeforces Round #770 (Div. 2)
VP
A | B | C | D | E |
---|---|---|---|---|
7min | 30min | 63min | 131min | |
+2 | +2 |
排名:rk485
基准分:\(\color{Purple}{1967}\)
A
\(\color{Gray}{800}\)
很明显,要么能有 \(2\) 种,否则就是 \(1\) 种,简单分讨即可。
时间复杂度:\(O(n)\)
int n,k;
const int N=2e5+10;
char s[N];
void work(){
cin>>n>>k>>(s+1);
bool f=1;
L(i,1,n/2)
if(s[i]!=s[n-i+1]) f=0;
if(f||!k) cout<<1<<'\n';
else cout<<2<<'\n';
}
B
\(\color{Cyan}{1400}\)
2B 1400 出题人怕不是有大病
题目似乎很难用常规的思路求解,考虑某些奇怪的角度切入。
明显 \(x\) 和 \(x+3\) 的奇偶性必然不同,考虑从奇偶性入手。
对于相加运算:
假设加上 \(y\),不管 \(y\) 的奇偶性如何,\(x+y\) 和 \(x+y+3\) 的奇偶性必然不同。
对于异或运算:
假设异或上 \(y\),因为 \(x\) 和 \(x+3\) 二进制下最后一位不同,异或后也不会相同。
所以,\(x \bmod 2\) 的值进行任意一次操作,对比 \(y \bmod 2\) 的值即可。
因为题目保证其一有解,所以可以确定。
时间复杂度:\(O(n)\)
int n,x,y;
const int N=2e5+10;
int a[N];
void work(){
cin>>n>>x>>y;
int t=x%2,g=y%2;
L(i,1,n) cin>>a[i];
L(i,1,n) t+=a[i];
cout<<((t%2==y%2)?"Alice":"Bob")<<'\n';
}
C
\(\color{Gray}{1000}\)
不难想到形如 \(\dots,5,7,9,\dots\) 和 \(\dots,6,8,10,12,\dots\) 的情况都能满足。
首先要把无解的情况,也就是\(n \bmod 2 = 1\) 时判掉。
不难想到这样为何无解,此时除非 \(m=1\) 时可以有解。
之后按照之前的状况构造即可。
时间复杂度:\(O(n\!k)\)
void work(){
cin>>x>>y;int c1=0,c2=1;
if((x&1)&&(y^1)) return cout<<"NO"<<'\n',void();
cout<<"YES"<<'\n';
L(i,1,x) L(j,1,y)
if(i&1) cout<<(c1++)*2+1<<" \n"[j==y];
else cout<<(c2++)*2<<" \n"[j==y];
}
不该被 B 吓死……
D
\(\color{Purple}{2000}\)
从 \(\color{Gray}{Newbie}\) 到 \(\color{Purple}{Candidate Master}\) 只是 CD 的差距
对样例手搓可知,\(4\) 次查询肯定能确定 \(2\) 个绝对不是 \(0\) 的数。
将两个可能是 \(0\) 的数带上,再对之后的数进行更新,重复之前的过程即可。
int n,x,y,a[5];
int ask(int x,int y,int z){
cout<<"? "<<x<<' '<<y<<' '<<z<<'\n';
cl;int g;cin>>g;return g;
}void work(){
cin>>n;int x,y,z=1,ma=0,c=0;
a[1]=ask(2,3,4);a[2]=ask(1,3,4);
a[3]=ask(1,2,4);a[4]=ask(1,2,3);
L(i,1,4) ma=max(ma,a[i]);
vector<int>p;
L(i,1,4){
if(a[i]!=ma||c==2)
p.push_back(i);
else c++;
}x=p[0],y=p[1];
while(z==x||z==y) z++;
L(i,5,n){
int X=ask(x,z,i),Y=ask(y,z,i);
if(max(X,Y)>ma){
ma=max(X,Y);
if(X>Y) y=i;else x=i;
}
}cout<<"! "<<x<<' '<<y<<'\n';cl;
}
E
\(\color{Red}{2400}\)
官方给出的解法是欧拉回路(好像),但窝太菜了,不会,没学,也就没写。
因为看到把元素分到两个集合中,还是可以想到用二分图去做。
首先可以想到,如果某个数字出现次数是奇数,就直接判为无解,这一过程可以用 std::map()
实现。
然后解决建模这个大问题,考虑加强限制。
对于每个数组分配对半这个条件,转化为每个数组中,相邻的数不得出现在同一集合。
即:对于数组 \(a\),所有满足条件的 \(i\),在 \(a_{2i-1}\) 和 \(a_{2i}\) 之间连边。
对于一半某数在左一半在右这个条件,转化为所有数中,相邻且相等的数不得出现在同一集合。
即:把所有数收集到 \(p\),排序,所有满足条件的 \(i\),在 \(p_{2i-1}\) 和 \(p_{2i}\) 之间连边。
尝试证明这样会产生一个二分图。
二分图的一个重要性质就是没有奇环。按上述方法连边,因为已经把出现奇数次的不合法情况排除了(但我赛时居然一开始没想到),所以每个点必定都只连两条边。
不难证明这样建出的图不存在奇环,所以如上建图之后跑二分图染色,之后按颜色输出方案即可。
赛时代码非常扭曲,可能参考意义不大
时间复杂度:\(O(\sum n \log_2 \sum n )\)
int m,tot;
const int N=2e5+10;
int n[N],cl[N],in[N];
vector<int>g[N];
vector<pi>a[N],p;
map<int,int>mp;
void dfs(int u,int f){
cl[u]=f;
for(int v:g[u]){
if(cl[v]) continue;
dfs(v,-f);
}
}void work(){
cin>>m;
L(i,1,m){
cin>>n[i];
L(j,1,n[i]){
int x;cin>>x;p.pb({x,tot});
a[i].pb({x,tot});mp[x]++;
in[tot]=i;
tot++;
}
}sort(p.begin(),p.end());
L(i,1,m) for(auto x:a[i])
if(mp[F(x)]&1) return cout<<"NO",void();
cout<<"YES"<<'\n';
L(i,1,m) for(int j=0;j<=a[i].size()-2;j+=2){
g[S(a[i][j])].pb(S(a[i][j+1]));
g[S(a[i][j+1])].pb(S(a[i][j]));
}for(int i=0;i<(int)p.size()-1;i++){
if(F(p[i])==F(p[i+1])){
g[S(p[i+1])].pb(S(p[i]));
g[S(p[i])].pb(S(p[i+1]));
i++;
}
}L(i,0,tot-1) if(!cl[i])dfs(i,1);
int cnt=0;
L(i,1,m){
L(j,1,n[i]){
cout<<(cl[cnt]==1?'L':'R');
cnt++;
}cout<<'\n';
}
}
对了,讨论区有暴论称,F可能跟D一个难度,也许之后去逝逝看但 \(\color{Salmon}{2600}\) 的评分怕不是在逗我。