なんとか解けてよかった。
https://atcoder.jp/contests/keyence2021/tasks/keyence2021_d
問題
正整数Nが与えられる。
2^N人の人がいるので、2^(N-1)人のチーム2つに分かれて、試合をするという作業を繰り返す。
何回か試合を行ったのち、2人の対で同じチームになった回数nと異なるチームになったmがどの対でも一致するようにしたい。
条件を満たす最小試合回数のチーム編成例を示せ。
解法
1試合で同じチームになれる人は2^(N-1)-1人、別のチームになれる人は2^(N-1)人である。
よって、n=2^(N-1)-1、m=2^(N-1)を達成できれば、試合回数が最小になる。
あとはその編成例を考えよう。
今2^k人に対し(2^k)-1試合で条件を満たす方法がわかったとする。
そこから、2^(k+1)人に対し(2^(k+1))-1試合で条件を満たす方法を構築しよう。
これは以下のようにすればよい。
k=3のケースを考える。
8人の組み合わせでは7試合が行われる。これの組み合わせをAとする。
まず、16人を前後半半々に分けたチームを作る(下記xとyに相当)
次に、Aを縦に二重化したものをさらに横に二重化し、14試合分の組み合わせを作る。
この時、二重化したうちの片方はチームを反転させる。(下記図で、A1は元のAの1試合目の組み合わせを示す)
こうすると、前後半に分けたチームは、互いに7回チームが一致し、8回チームが異なる状況を作り出せる。
xxxxxxxxyyyyyyyy ---A1------A1--- ---A1------A1'-- ---A2------A2--- ---A2------A2'-- ... ---A7------A7--- ---A7------A7'--
int N; int C[9][512][512]; int D[256][256]; void solve() { int i,j,k,l,r,x,y; string s; cin>>N; C[1][0][0]=0; C[1][0][1]=1; for(i=2;i<=N;i++) { FOR(x,1<<i) C[i][0][x]=x; int s=1<<(i-2); FOR(x,((1<<i)-2)) { FOR(y,s) { C[i][x*2+1][y]=C[i][x*2+2][y]=C[i-1][x][y]; C[i][x*2+1][y+2*s]=C[i][x*2+2][y+2*s]=C[i-1][x][y+s]; C[i][x*2+1][y+s]=C[i][x*2+2][y+3*s]=C[i-1][x][y]+2*s; C[i][x*2+1][y+3*s]=C[i][x*2+2][y+s]=C[i-1][x][y+s]+2*s; } } } cout<<((1<<N)-1)<<endl; FOR(i,((1<<N)-1)) { string S; S.resize(1<<N); int t=(1<<N)/2; FOR(x,t) S[C[N][i][x]]='A'; FOR(x,t) S[C[N][i][x+t]]='B'; cout<<S<<endl; } }
まとめ
倍々ゲームで対応できるのはすぐ予想がついたが、詰め切るのに手間取った。