[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 }