1. 程式人生 > >[BZOJ4032][HEOI2015]最短不公共子串(Trie+DP)

[BZOJ4032][HEOI2015]最短不公共子串(Trie+DP)

在虐各種最長公共子串、子序列的題虐的不耐煩了之後,你決定反其道而行之——被它們虐。

操作一:對A,B分別建SAM,暴力BFS。

操作二:對B建序列自動機或SAM,A在上面暴力匹配。

操作三:對A,B建序列自動機,暴力匹配。

操作四:對B建序列自動機,在自動機上DP。

上面的我一句也看不懂,對不起我重說一遍。

操作一:對B的所有後綴建Trie,A在上面暴力跑。$O(n^2)$

操作二:列舉A的子串,在B上暴力匹配。$O(n^2)$

操作三:在B的每個點上掛一個原本沒有的葉子,將從根到這個葉子的路徑形成的串扔到A上暴力跑匹配,若A有這個串則更新答案(因為是新葉子故B肯定沒有這個串)。但這樣似乎是$O(n^3*26)$的,注意列舉點的順序,按建立順序從後往前列舉,對於所有深度>=當前ans的直接跳過,這樣就近似為$O(n^2*26)$了。

操作四:DP,f[i][j]表示A的前i個字元中選j個,在B的最小匹配末尾下標的最大值。每次只要從f[pre[i][c]][j-1]轉移,其中pre[i][c]為A的第i個位置前的最接近i的字母c的位置。$O(n^2*26)$

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 5 using namespace std;
 6 
 7 const int
N=2010,M=2000100,inf=1e9; 8 int n,m,nd=1,ans,son[M][27],fa[M],dep[M],pre[N][27],nxt[N][27],f[N][N]; 9 char st[M],A[N],B[N],s[N]; 10 11 void ins(int d){ 12 int x=1; 13 rep(i,d,m){ 14 int c=B[i]-'a'+1; 15 if (!son[x][c]) son[x][c]=++nd,fa[nd]=x,st[nd]=B[i],dep[nd]=dep[x]+1;
16 x=son[x][c]; 17 } 18 } 19 20 void walk(int d){ 21 int x=1; 22 rep(i,d,n){ 23 int c=A[i]-'a'+1; 24 if (!son[x][c]) { ans=min(ans,i-d+1); return; } 25 x=son[x][c]; 26 } 27 } 28 29 void work(int d){ 30 int p=d; 31 for (int i=1; i<=m && p<=n; i++) 32 if (B[i]==A[p]) p++; 33 if (p<=n) ans=min(ans,p-d+1); 34 } 35 36 void work2(int tot){ 37 int p=1; 38 for (int i=1; i<=n && p<=tot; i++) 39 if (A[i]==s[p]) p++; 40 if (p>tot) ans=min(ans,tot); 41 } 42 43 void solve1(){ 44 ans=inf; 45 rep(i,1,n) walk(i); 46 printf("%d\n",ans==inf ? -1 : ans); 47 } 48 49 void solve2(){ 50 ans=inf; 51 rep(i,1,n) work(i); 52 printf("%d\n",ans==inf ? -1 : ans); 53 } 54 55 void solve3(){ 56 ans=inf; 57 for (int i=nd; i; i--) if (dep[i]<ans){ 58 int tot=0; 59 for (int k=i; k>1; k=fa[k]) s[++tot]=st[k]; 60 reverse(s+1,s+tot+1); tot++; 61 rep(j,1,26) if (!son[i][j]) s[tot]=j+'a'-1,work2(tot); 62 } 63 printf("%d\n",ans==inf ? -1 : ans); 64 } 65 66 void solve4(){ 67 ans=inf; 68 rep(i,2,n){ 69 rep(j,1,26) pre[i][j]=pre[i-1][j]; 70 pre[i][A[i-1]-'a'+1]=i-1; 71 } 72 for (int i=n-1; ~i; i--){ 73 rep(j,1,26) nxt[i][j]=nxt[i+1][j]; 74 nxt[i][B[i+1]-'a'+1]=i+1; 75 } 76 rep(i,1,n){ 77 int t=nxt[0][A[i]-'a'+1]; 78 if (t) f[i][1]=max(f[i][1],t); else { puts("1"); return; } 79 } 80 rep(i,1,n) rep(j,2,i) rep(k,1,26) if (pre[i][k]){ 81 int t=nxt[f[pre[i][k]][j-1]][A[i]-'a'+1]; 82 if (!t) { ans=min(ans,j); break; } 83 f[i][j]=max(f[i][j],t); 84 } 85 printf("%d\n",ans==inf ? -1 : ans); 86 } 87 88 int main(){ 89 freopen("bzoj4032.in","r",stdin); 90 freopen("bzoj4032.out","w",stdout); 91 scanf("%s%s",A+1,B+1); n=strlen(A+1); m=strlen(B+1); 92 rep(i,1,m) ins(i); 93 solve1(); solve2(); solve3(); solve4(); 94 return 0; 95 }