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

 

 

posted @ 2018-10-31 19:25  HocRiser  阅读(176)  评论(0编辑  收藏  举报