Codeforces Round #770 (Div. 2)

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}\)

CF1634A Reverse and Concatenate

很明显,要么能有 \(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}\)

CF1634B Fortune Telling

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}\)

CF1634C OKEA

不难想到形如 \(\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}\)

CF1634D Finding Zero

\(\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}\)

CF1634E Fair Share

官方给出的解法是欧拉回路(好像),但窝太菜了,不会,没学,也就没写。

因为看到把元素分到两个集合中,还是可以想到用二分图去做。
首先可以想到,如果某个数字出现次数是奇数,就直接判为无解,这一过程可以用 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}\) 的评分怕不是在逗我

posted @ 2022-08-25 15:22  AIskeleton  阅读(15)  评论(0编辑  收藏  举报