BZOJ4032: [HEOI2015]最短不公共子串
n<=2000的两个串,求四个问:
(1) A的一个最短的子串,它不是B的子串
(2) A的一个最短的子串,它不是B的子序列
(3) A的一个最短的子序列,它不是B的子串
(4) A的一个最短的子序列,它不是B的子序列
一开始??????嗯要识别子串和子序列需要俩东西:序列自动机和后缀自动机。
前两问:枚举A的起点直接在两个自动机里走即可。
后两问:
方法一:(x,y)表示A的序列自动机上第x位和B的后缀/序列自动机上第y位匹配上时的最短串。从两个根节点开始bfs一次即可。复杂度n*n*26,空间巨大。
方法二:只留一个状态y,把x当作一种转移途径,从左到右枚举A串字符,使B的自动机上所有和当前字符相同的转移路径进行一次转移。复杂度n*n。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 //#include<iostream> 6 using namespace std; 7 8 int n,m; 9 #define maxn 4011 10 char a[maxn],b[maxn]; 11 12 struct seAM 13 { 14 int ch[maxn][26],pre[maxn],last[26]; 15 seAM() {pre[1]=0; for (int i=0;i<26;i++) last[i]=1;} 16 int idx(char c) {return c-'a';} 17 void insert(char c,int p) 18 { 19 int id=idx(c);p++; 20 pre[p]=last[id]; 21 for (int i=0;i<26;i++) 22 for (int j=last[i];j && !ch[j][id];j=pre[j]) ch[j][id]=p; 23 last[id]=p; 24 } 25 }sb; 26 27 struct SAM 28 { 29 struct Node 30 { 31 int ch[26],pre,pos; 32 Node() {memset(ch,0,sizeof(ch)); pre=0;} 33 }a[maxn]; 34 int size,last,root; 35 SAM() {root=1; a[1].pos=0; size=1; last=1;} 36 int idx(char c) {return c-'a';} 37 void insert(char c,int p) 38 { 39 int id=idx(c),x=++size; 40 a[x].pos=p; 41 int y=last; 42 for (;y && !a[y].ch[id];y=a[y].pre) a[y].ch[id]=x; 43 last=x; 44 if (!y) a[x].pre=root; 45 else if (a[a[y].ch[id]].pos==a[y].pos+1) a[x].pre=a[y].ch[id]; 46 else 47 { 48 int z=a[y].ch[id],w=++size; 49 a[w]=a[z]; a[w].pos=a[y].pos+1; 50 a[z].pre=a[x].pre=w; 51 for (;y && a[y].ch[id]==z;y=a[y].pre) a[y].ch[id]=w; 52 } 53 } 54 }sam; 55 56 int f[maxn]; 57 int main() 58 { 59 scanf("%s%s",a+1,b+1);n=strlen(a+1);m=strlen(b+1); 60 for (int i=1;i<=m;i++) sb.insert(b[i],i),sam.insert(b[i],i); 61 int ans; 62 63 ans=n+1; 64 for (int i=1;i<=n;i++) 65 { 66 int p=sam.root,j; 67 for (j=i;p && j<=n;j++) p=sam.a[p].ch[a[j]-'a']; 68 if (!p) ans=min(ans,j-i); 69 } 70 if (ans>n) puts("-1");else printf("%d\n",ans); 71 72 ans=n+1; 73 for (int i=1;i<=n;i++) 74 { 75 int p=1,j; 76 for (j=i;p && j<=n;j++) p=sb.ch[p][a[j]-'a']; 77 if (!p) ans=min(ans,j-i); 78 } 79 if (ans>n) puts("-1");else printf("%d\n",ans); 80 81 ans=n+1; 82 memset(f,0x3f,sizeof(f)); 83 f[1]=0; 84 for (int i=1;i<=n;i++) 85 for (int j=sam.size;j>=1;j--) 86 { 87 int tmp;if (!(tmp=sam.a[j].ch[a[i]-'a'])) ans=min(ans,f[j]+1); 88 else f[tmp]=min(f[tmp],f[j]+1); 89 } 90 if (ans>n) puts("-1");else printf("%d\n",ans); 91 92 ans=n+1; 93 memset(f,0x3f,sizeof(f)); 94 f[1]=0; 95 for (int i=1;i<=n;i++) 96 for (int j=m+1;j>=1;j--) 97 { 98 int tmp;if (!(tmp=sb.ch[j][a[i]-'a'])) ans=min(ans,f[j]+1); 99 else f[tmp]=min(f[tmp],f[j]+1); 100 } 101 if (ans>n) puts("-1");else printf("%d\n",ans); 102 103 return 0; 104 }