洛谷P3763 [TJOI2017]DNA(后缀自动机)

传送门

好像用SAM写的很少诶……

其实我一开始也没想到要用SAM的……主要是没有想到找的时候可以dfs……

首先建一个SAM,然后跑一遍dfs,枚举一下下一位,如果相同直接继续,否则就花费一次次数来改变它,保证改变次数小于等于3就行了

 1 // luogu-judger-enable-o2
 2 //minamoto
 3 #include<iostream>
 4 #include<cstdio>
 5 #include<cstring>
 6 using namespace std;
 7 const int N=1e6+5;
 8 int cnt[N<<1],fa[N<<1],ch[N<<1][4],l[N<<1],last,tot;
 9 char s[N];int c[N],a[N],ans,m,val[N];
10 void ins(int c){
11     int p=last,np=++tot;last=np,l[np]=l[p]+1,cnt[np]=1;
12     for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
13     if(!p) fa[np]=1;
14     else{
15         int q=ch[p][c];
16         if(l[q]==l[p]+1) fa[np]=q;
17         else{
18             int nq=++tot;l[nq]=l[p]+1;
19             memcpy(ch[nq],ch[q],sizeof(ch[q]));
20             fa[nq]=fa[q],fa[q]=fa[np]=nq;
21             for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
22         }
23     }
24 }
25 inline void calc(){
26     memset(c,0,sizeof(c));
27     for(int i=1;i<=tot;++i) ++c[l[i]];
28     for(int i=1;i<=tot;++i) c[i]+=c[i-1];
29     for(int i=1;i<=tot;++i) a[c[l[i]]--]=i;
30     for(int i=tot,p;i;--i)
31     p=a[i],cnt[fa[p]]+=cnt[p];
32 }
33 void dfs(int p,int len,int j){
34     if(len>m) return (void)(ans+=cnt[p]);
35     for(int i=0;i<4;++i){
36         if(!ch[p][i]) continue;
37 //        val[s[len]]==i?dfs(ch[p][i],len+1,j):j<3?dfs(ch[p][i],len+1,j+1):(void)(1);
38         if(val[s[len]]==i) dfs(ch[p][i],len+1,j);
39         else if(j<3) dfs(ch[p][i],len+1,j+1);
40     }
41 }
42 int main(){
43 //    freopen("testdata.in","r",stdin);
44     val['T']=0,val['A']=1,val['C']=2,val['G']=3;
45     int T;scanf("%d",&T);
46     while(T--){
47         memset(ch,0,sizeof(ch)),memset(cnt,0,sizeof(cnt));
48         last=tot=1,ans=0;
49         scanf("%s",s+1);int len=strlen(s+1);
50         for(int i=1;i<=len;++i) ins(val[s[i]]);
51         calc();
52         scanf("%s",s+1),m=strlen(s+1);
53         dfs(1,1,0);printf("%d
",ans);
54     }
55     return 0;
56 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9643215.html