CodeForces 1286A Garland (R1700)
問題
長さの数列が与えられます。これは長さの順列の一部が欠けたもので、欠けたところはになっています。 が順列になるように復元したときの、の複雑さの最小値を求めてください。ここでの複雑さとは、隣接要素のペアであって、偶奇が異なるようなものの個数とします。
制約
考察
偶奇だけが重要なのでで考えます。まず、をで割った余りで置き換えておきます(だったところはとします)。左から順番に復元していくことにします。すると、それまでに使ったの個数と、最後の要素の偶奇が同じであれば、後のことを考えるとコストが小さいほうがよいので、次のようなDPが考えられます。
$$ dp[i][j][k]:=左からi個復元して、それまでで0をj個使っていて、最後の要素の偶奇がkのときのコストの最小値 $$ 使ったの個数はなので状態として持たなくて良いです。
からの遷移は
を置く場合 $$ chmin(dp[i+1][j+1][0],dp[i][j][k]+k) $$
を置く場合
$$ chmin(dp[i+1][j][1],dp[i][j][k]+(k\ xor\ 1)) $$
です。とが置ける個数はそれぞれとなので、これを超えないようにしなければなりません。
#include<bits/stdc++.h> using namespace std; const int INF=0x3f3f3f3f; int dp[110][110][2]; int main() { int N; cin>>N; vector<int> p(N); for(int i=0;i<N;i++) cin>>p[i]; if(N==1){ cout<<0<<endl; return 0; } for(int i=0;i<N;i++){ if(p[i]==0) p[i]=-1; else p[i]=p[i]%2; } memset(dp,INF,sizeof(dp)); if(p[0]==0 or p[0]==-1) dp[1][1][0]=0; if(p[0]==1 or p[0]==-1) dp[1][0][1]=0; for(int i=1;i<N;i++) for(int j=0;j<=i;j++) for(int k=0;k<2;k++) if(dp[i][j][k]<INF){ if((p[i]==0 or p[i]==-1) and j<N/2){ dp[i+1][j+1][0]=min(dp[i+1][j+1][0],dp[i][j][k]+(k^0)); } if((p[i]==1 or p[i]==-1) and i-j<(N+1)/2){ dp[i+1][j+0][1]=min(dp[i+1][j+0][1],dp[i][j][k]+(k^1)); } } cout<<min(dp[N][N/2][0],dp[N][N/2][1])<<endl; return 0; }
すでに数字が置かれているところも置かれていないとしています(置く数は決まっている)。こうすると最初にをたくさん使ってしまって、すでに決まっているところで置けないみたいになることがありますが、そのようなところからは遷移しないようにしているので大丈夫です。
感想
すでに置かれているところも新たに置くことにすると実装が軽くなりました。Editorialには貪欲法が書かれていましたがよく分かりませんでした。