Gym 101239E BZOJ 4110 Evolution in Parallel (DP、結論)
阿新 • • 發佈:2021-01-12
題目連結
(Gym) https://codeforces.com/gym/101239
(BZOJ) 大人,時代變了。
題解
這題好神仙啊
首先有一個顯然的 DP,按長度從小到大排序,維護一下目前可選的方案中除了 \(i\) 所在的組之外的組的最後一個元素都有哪些可能性。在 \(O(L)\) 時間內判斷一個串是否是另一個的子序列,時間複雜度 \(O(n^2L)\).
但是這樣並不能過,有一個很神仙的結論是,任何一個時刻有用的可選的方案只有至多 \(2\) 種!
這可以用數學歸納法證明。最一開始顯然只有一種可選方案。
如果某一時刻只有一種可選方案(不妨設為 \((i-1,x)\)),那麼下一個時刻只有可能出現 \((i,x)\)
如果某一時刻有兩種可選方案(不妨設為 \((i-1,x)\) 和 \((i-1,y)\)):
如果 \((i-1)\) 是 \(i\) 的子序列,那麼 \((i,x)\) 和 \((i,y)\) 都會成為候選集合。這時 \((i,i-1)\) 還有可能成為候選集合,但是我們注意到如果 \((i,i-1)\) 成為了候選集合,那麼 \(x\) 和 \(y\) 至少有一個是 \((i-1)\) 的子序列,這意味著 \((i,i-1)\) 可以被 \((i,x)\) 和 \((i,y)\) 完全替代!所以我們可以捨棄 \((i,i-1)\) 這種可能性,可選集合最多還是隻有 \(2\)
否則,可選集合只可能有 \((i,i-1)\) 這一種。
所以轉移就可以了,時間複雜度 \(O(nL)\).
程式碼
#include<bits/stdc++.h> #define llong long long #define mkpr make_pair #define x first #define y second #define iter iterator #define riter reverse_iterator #define y1 Lorem_ipsum_ #define tm dolor_sit_amet_ #define pii pair<int,int> using namespace std; inline int read() { int x = 0,f = 1; char ch = getchar(); for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;} for(; isdigit(ch);ch=getchar()) {x = x*10+ch-48;} return x*f; } const int mxN = 4000; int n; string a[mxN+3]; vector<pii> s[mxN+3]; vector<int> ans[2]; bool cmp_len(string s,string t) {return s.length()<t.length();} bool judge(int u,int v) { for(int i=0,j=0; i<a[u].length(); i++) { while(j<a[v].length()&&a[v][j]!=a[u][i]) {j++;} if(j==a[v].length()) {return false;} j++; } return true; } int main() { n = read(); cin>>a[n+1]; for(int i=1; i<=n; i++) cin>>a[i]; sort(a+1,a+n+1,cmp_len); for(int i=1; i<=n; i++) if(!judge(i,n+1)) {puts("impossible"); return 0;} s[0].push_back(mkpr(0,0)); for(int i=1; i<=n; i++) { if(s[i-1].size()==1) { if(judge(i-1,i)) {s[i].push_back(mkpr(s[i-1][0].x,i-1));} if(i-1!=s[i-1][0].x&&judge(s[i-1][0].x,i)) {s[i].push_back(mkpr(i-1,s[i-1][0].x));} } else if(s[i-1].size()==2) { if(judge(i-1,i)) {s[i].push_back(mkpr(s[i-1][0].x,i-1)); s[i].push_back(mkpr(s[i-1][1].x,i-1));} else if(judge(s[i-1][0].x,i)) {s[i].push_back(mkpr(i-1,s[i-1][0].x));} else if(judge(s[i-1][1].x,i)) {s[i].push_back(mkpr(i-1,s[i-1][1].x));} } if(!s[i].size()) {puts("impossible"); return 0;} } for(int i=n,j=s[n][0].x,x=0; i>=1; i--) { ans[x].push_back(i); for(int k=0; k<s[i].size(); k++) if(s[i][k].x==j) { if(s[i][k].x==i-1) {x^=1; j = s[i][k].y;} else {j = s[i][k].x;} break; } } printf("%d %d\n",ans[0].size(),ans[1].size()); for(int i=ans[0].size(); i>=1; i--) cout<<a[ans[0][i-1]]<<endl; for(int i=ans[1].size(); i>=1; i--) cout<<a[ans[1][i-1]]<<endl; return 0; }