Codeforces Round #629 (Div. 3)-D 「Carousel」
Problem - D - Codeforces
問題概要は
「n個の模様を円形にならべたカルーセルについて、隣り合う模様が異なるときは違う色に塗る。このとき使用する色の最小数と、その塗り方を答えよ」
というものです。ちなみにカルーセルはメリーゴーランドという意味の言葉なんですね、知らなかったです。
◇さて、まずすべての模様が同じ場合は1色で塗ればよいですね。すべて1で塗ります。
以下、異なる模様が存在する場合を考えます。
◇nが偶数のときは、隣り合う模様が異なるかどうかによらず、1と2で交互に塗れば良いです。なぜかというと、例えばn=6のとき、
1-2-1-2-1-2 となり、1番目と6番目の色が異なります。nが偶数であれば問題なく2色で塗れるわけです。
◇やっかいなのがnが奇数のときです。以下の3パターンに分かれます。
①1番目とn番目が同じ模様の場合
...この場合は、nが偶数のときと同様に1と2で交互に塗れば良いです。1番目とn番目は同じ模様なので、同じ色で塗ってokです。
②どの模様も隣り合う模様と異なっているとき
...この場合は1と2で交互に塗っていくしかないですが、n番目の模様を1で塗る(nは奇数なので)とき、1番目の模様も1で塗られていて被ってしまいます。そのため、n番目の模様を3で塗ります。3色必要ですね。
③同じ模様が隣り合っている箇所がある場合
...①のパターンを含みます。この場合は隣り合っている部分の2つの模様を同じ色で塗り、それ以外は1と2を交互に塗る方法で良いです。例えばn=3のとき、
1-2-1-2-2-1-2 となります。1か所だけ同じ色で連続して塗れば、n番目は2で塗られ、1番目の1と異なります。
やや複雑でしたが、そこまで難しい考察は必要ない問題ですね。僕は解けていないんですが()
↓コードです。
int main() { ll q; cin >> q; while(q--){ ll n; cin >> n; vector<ll> t(n); bool ok=true; //すべて同じ模様ならtrue rep(i,n){ cin >> t[i]; if(i){ if(t[i]!=t[i-1]) ok=false; } } //すべて同じ模様の場合 if(ok){ cout << 1 << endl; rep(i,n){ if(i) cout << " "; cout << 1; } cout << endl; continue; } //nが偶数のとき if(n%2==0){ cout << 2 << endl; rep(i,n){ if(i) cout << " "; if(i%2==0) cout << 1; else cout << 2; } cout << endl; continue; } ll p=1; ll q=2; ll pos=-1; //奇数の場合1 if(t[n-1]==t[0]){ cout << 2 << endl; rep(i,n){ if(i) cout << " "; if(i%2==0) cout << 1; else cout << 2; } cout << endl; continue; } rep(i,n){ if(i){ if(t[i]==t[i-1]){ pos=i; break; } } } //奇数の場合2 if(pos==-1){ cout << 3 << endl; rep(i,n){ if(i) cout << " "; if(i==n-1){ cout << 3; break; } if(i%2==0) cout << 1; else cout << 2; } cout << endl; continue; } //奇数の場合3 cout << 2 << endl; rep(i,n){ if(i) cout << " "; if(i==pos){ p=2; q=1; } if(i%2==0) cout << p; else cout << q; } cout << endl; } return 0; }
奇数の場合の①と③はまとめてしまった方がきれいなコードかもしれません。
類題としてはAGC035-A「XOR Circle」等が挙げられそうです(こちらは実装というより考察が必要です)。
atcoder.jp