洛谷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\n",ans); 54 } 55 return 0; 56 }
深深地明白自己的弱小