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。
  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 }
View Code

 

posted @ 2017-12-09 07:27  Blue233333  阅读(392)  评论(0编辑  收藏  举报