bzoj4032: [HEOI2015]最短不公共子串(SAM+DP)

4032: [HEOI2015]最短不公共子串

题目:传送门 


题解:

   陈年老题良心%你赛膜爆嘎爷

   当初做题...一眼SAM...结果只会两种直接DP的情况...

   情况1: 直接设f[i][j] 表示的是a串的第i个位置和b串的第j个位置开始的最长公共前缀(灵感来源于SA)。然后就枚举开头直接瞎搞啊。。。

   情况2: 定义一个last[i][j] 表示b串的位置i后面的第一个字符j,贪心的思想直接做,匹配不到位置就直接记录答案了嘛

   情况3: 因为是在b串当中找子串,a中找子序列,那就考虑对b建SAM,然后定义da[] 表示的是a串的第i个位置结尾的串在b串中跑到第j个状态的最短长度(具体看代码)、

   情况4: 利用情况2预处理的last,贪心思想,仿照情况三把last当作自动机来跑

    


代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #define inf 1e9 
 7 using namespace std;
 8 struct SAM
 9 {
10     int son[50];
11 }ch[5100];int cnt,dep[5100],a[5100],fail[5100],da[5100],la,root,ss;、
12 //da 表示的是a串的第i个位置结尾的串在b串中跑到第j个状态的最短长度 
13 void add(int k)
14 {
15     int x=a[k];
16     int p=la,np=++cnt;dep[np]=k;
17     while(p!=0 && ch[p].son[x]==0)ch[p].son[x]=np,p=fail[p];
18     if(p==0)fail[np]=root;
19     else
20     {
21         int q=ch[p].son[x];
22         if(dep[p]+1==dep[q])fail[np]=q;
23         else
24         {
25             int nq=++cnt;dep[nq]=dep[p]+1;
26             ch[nq]=ch[q];fail[nq]=fail[q];fail[np]=fail[q]=nq;
27             while(p && ch[p].son[x]==q)ch[p].son[x]=nq,p=fail[p];
28         }
29     }
30     la=np;
31 }
32 int len1,len2,opt;
33 int c[50],last[2100][50];//位置i后面的第一个字符j 
34 char sa[2100],sb[2100];
35 int f[2100][2100];//分别以i,j位置开头的最长公共前缀
36 int main()
37 {
38     //freopen("a.in","r",stdin);
39     //freopen("a.out","w",stdout);
40     //scanf("%d",&opt);
41     scanf("%s",sa+1);len1=strlen(sa+1);
42     scanf("%s",sb+1);len2=strlen(sb+1);
43     //if(opt==1)
44     //{
45         memset(f,0,sizeof(f));int ans=inf,len=0,maxx=0;
46         for(int i=len1;i>=1;i--)for(int j=len2;j>=1;j--)if(sa[i]==sb[j])f[i][j]=f[i+1][j+1]+1;
47         for(int i=1;i<=len1;i++)
48         {        
49             maxx=0;for(int j=1;j<=len2;j++)maxx=max(maxx,f[i][j]);
50             if(maxx!=len1-i+1)ans=min(ans,maxx+1);//加一定不相等 
51         }
52         if(ans==inf)printf("-1
");
53         else printf("%d
",ans);
54     //}
55     //else if(opt==2)
56     //{
57         len=0,ans=inf;for(int i=1;i<=50;i++)c[i]=inf;sb[0]='a';
58         for(int i=len2;i>=0;i--){for(int j=1;j<=26;j++)last[i][j]=c[j];c[sb[i]-'a'+1]=i;}
59         for(int i=1;i<=len1;i++)
60         {
61             len=0;
62             for(int j=i;j<=len1;j++)
63             {
64                 len=last[len][sa[j]-'a'+1];
65                 if(len>len1){ans=min(ans,j-i+1);break;}//跳出去证明没有了
66             }
67         }
68         if(ans==inf)printf("-1
");
69         else printf("%d
",ans);
70     //}
71 //    else if(opt==3)
72 //    {
73         cnt=0;root=la=++cnt;memset(da,63,sizeof(da));
74         for(int i=1;i<=len2;i++)a[i]=sb[i]-'a';for(int i=1;i<=len2;i++)add(i);ss=0;da[1]=0;ans=inf;
75         for(int i=1;i<=len1;i++)
76             for(int j=1;j<=cnt;j++)
77             {
78                 ss=ch[j].son[sa[i]-'a'];
79                 if(ss==0)ans=min(ans,da[j]+1);else da[ss]=min(da[ss],da[j]+1);
80             }
81         if(ans==inf)printf("-1
");
82         else printf("%d
",ans);
83 //    }
84     //else if(opt==4)
85     //{
86         ans=inf;//for(int i=1;i<=50;i++)c[i]=inf;sb[0]='a';
87         //for(int i=len2;i>=0;i--){for(int j=1;j<=26;j++)last[i][j]=c[j];c[sb[i]-'a'+1]=i;}
88         memset(da,63,sizeof(da));da[0]=0;ss=0;
89         for(int i=1;i<=len1;i++)
90             for(int j=len2;j>=0;j--)
91             {
92                 ss=last[j][sa[i]-'a'+1];
93                 if(ss>len1)ans=min(ans,da[j]+1);else da[ss]=min(da[ss],da[j]+1);
94             }
95         if(ans==inf)printf("-1
");
96         else printf("%d
",ans);
97     //}
98     return 0;
99 }
原文地址:https://www.cnblogs.com/CHerish_OI/p/8783224.html