TopCoder SRM 263 Div1 Medium HardDequeSort
問題
双方向キューをいくつか使って、与えられた数列を次のようにソートする。
数列の先頭から項を見ていき、
- すでにある双方向キューどれかの先頭にその項を追加する
- すでにある双方向キューどれかの末尾にその項を追加する
- 新しい双方向キューを作り、その唯一の要素をその項とする
の操作を繰り返し、
最後に双方向キューを好きな順番に組み合わせて、一つの列にする。
結果の列がソートされているためには、最低でいくつの双方向キューを作らなければならないか、求めよ。
制約条件
-1000≦数列の各項≦1000
数列の項数≦50
方針
自分がやったのは、以下のようなO(n^3)のDP.
dp[l][r]を、数列のうち、l番目以上r番目未満の項だけを取り出したものソートするのに必要なキューの数の最小値とする。
l番目以上r番目未満の項だけを取り出したものが、一つのキューだけでつくれるなら1を返す。
無理なら、dp[l][i]+dp[i][r]に分割する。
全ての分割の仕方を試せばいい。
ソースコード
int n,d[52],v[52]; int dp[52][52]; bool ck(vi &v){ int n=v.size(), b, s; b=s=v[0]; rep(i,n){ if(s<v[i]&&v[i]<b)return 0; s=min(s,v[i]); b=max(b,v[i]); } return 1; } int rec(int l,int r){ int &res=dp[l][r]; if(res>=0)return res; vi tmp; rep(i,n)if(v[l]<=d[i]&&d[i]<=v[r-1])tmp.pb(d[i]); if(ck(tmp))return res=1; res=inf; for(int i=l+1;i<r;i++)res=min(res,rec(l,i)+rec(i,r)); return res; } class HardDequeSort { public: int minDeques(vector <int> data) { n=data.size(); rep(i,n)d[i]=v[i]=data[i]; sort(v,v+n); memset(dp,-1,sizeof(dp)); return rec(0,n); } };