2017 暑假艾教集训 day10 AC自动机+马拉车+后缀数组 +kmp
来源:互联网 发布:女童白色运动鞋淘宝 编辑:程序博客网 时间:2024/06/05 05:17
https://vjudge.net/contest/177933#overview
H HDU3068
做法:马拉车模板
#include <bits/stdc++.h>using namespace std;const int maxn= 110015;char s[maxn];char str[maxn*2];int dp[maxn*2];int mlc(){ int n=strlen(s+1); str[0]='@'; for(int i=2;i<=2*n;i+=2) { str[i-1] = '#' ; str[i]=s[i/2] ; } str[2*n+1] = '#'; str[2*n+2] = '0'; str[2*n+3] = 0; memset(dp,0,sizeof(dp)); int ans=0 ,mx=0,id=0; for(int i=1;i<=2*n+1;++i) { mx>i? dp[i]=min(dp[2*id-i],mx-i) :dp[i]=1 ; while(str[i-dp[i]] == str[i+dp[i]]) dp[i]++; if(dp[i]+i>mx) { mx=dp[i]+i; id=i; } ans=max(ans,dp[i]); } return ans-1;}int main(){ while(scanf("%s",s+1)!=EOF) { printf("%d\n",mlc()); } return 0;}
POJ 2406
做法: KMP 最小循环节 N-NEXT[N] 前提(N%(N-NEXT[N])==0)
#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>using namespace std;const int maxn=1e6+10;char s[maxn];int next[maxn];int len;void getnext(){ int j,k; j=0; next[0] = k =-1; while(j<len) { if(k==-1 || s[j]==s[k]) next[++j]=(++k); else k=next[k]; }}int main(){ while(scanf("%s",s)!=EOF) { if(s[0]=='.') break; len=strlen(s); getnext(); int temp = len-next[len]; if(len%temp==0) { printf("%d\n",len/temp); } else { printf("1\n"); } } return 0;}
HDU 2222
做法:AC自动机模板
#include <bits/stdc++.h>using namespace std;struct trie{ int next[500010][26],fail[500010],end[500010]; int root , tot; int newnode() { for(int i=0;i<26;++i) { next[tot][i]=-1; } end[tot++] = 0; return tot-1; } void init() { tot=0; root = newnode(); } void push(char str[]) { int len=strlen(str); int now=root; for(int i=0;i<len;++i) { if(next[now][str[i]-'a']== -1) { next[now][str[i]-'a'] = newnode(); } now = next[now][str[i]-'a']; } end[now]++; } void build() { queue<int> que; fail[root] = root; for(int i=0;i<26;++i) { if(next[root][i]==-1) next[root][i]=root; else { fail[next[root][i]]=root; que.push(next[root][i]); } } while(!que.empty()) { int now=que.front() ; que.pop(); for(int i=0;i<26;++i) { if(next[now][i]==-1) { next[now][i]=next[fail[now]][i]; } else { fail[next[now][i]]=next[fail[now]][i]; que.push(next[now][i]); } } } } int query(char str[]) { int len=strlen(str); int now=root; int ans=0; for(int i=0;i<len;++i) { now= next[now][str[i]-'a']; int temp = now; while(temp!=root) { ans+=end[temp]; end[temp]=0; temp=fail[temp]; } } return ans; }}ac;char s[1000010];int main(){ int T,n; scanf("%d",&T); while(T--) { scanf("%d",&n); ac.init(); for(int i=0;i<n;++i) { scanf("%s",s); ac.push(s); } ac.build(); scanf("%s",s); printf("%d\n",ac.query(s)); } return 0;}
POJ 2778
做法:只需要把病毒串标记。然后对没有标记在矩阵上记录权值(如果next节点不存在也要记录),套一个矩阵快速幕即可!
#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;typedef long long ll;const ll mod =1e5;struct matirx{ ll mu[105][105]; matirx() { for(int i=0;i<105;++i) { for(int j=0;j<105;++j) { mu[i][j]=0; } } }};int turn(char c){ if(c=='A') return 0; if(c=='G') return 1; if(c=='C') return 2; if(c=='T') return 3;}struct tire{ int next[105][4],fail[105],end[105]; int root,tot; int newnode() { for(int i=0;i<4;++i) { next[tot][i]=-1; } end[tot++]=0; return tot-1; } void init() { tot=0; root=newnode(); } void push(char str[]) { int len=strlen(str); int now=root; for(int i=0;i<len;++i) { if(next[now][turn(str[i])]==-1) { next[now][turn(str[i])] = newnode(); } now=next[now][turn(str[i])]; } end[now]=1; } void build() { queue<int> que; fail[root] = root; for(int i=0;i<4;++i) { if(next[root][i]==-1) { next[root][i]=root; } else { fail[next[root][i]] = root; que.push(next[root][i]); } } while(!que.empty()) { int now=que.front() ;que.pop(); if(end[fail[now]]) end[now]=1; for(int i=0;i<4;++i) { if(next[now][i]==-1) { next[now][i]=next[fail[now]][i]; } else { fail[next[now][i]] = next[fail[now]][i]; que.push(next[now][i]); } } } }}ac;matirx muilt(matirx a ,matirx b){ matirx ans; for(int i=0;i<ac.tot;++i) { for(int k=0;k<ac.tot;++k) { for(int j=0;j<ac.tot;++j) { ans.mu[i][j] = ( ans.mu[i][j] + a.mu[i][k] * b.mu[k][j] )%mod;; } } } return ans;}matirx pow(matirx bit ,ll n){ matirx ans; for(int i=0;i<ac.tot;++i) ans.mu[i][i]=1; while(n) { if( n & 1) ans = muilt(ans,bit); bit = muilt(bit,bit); n>>=1; } return ans;}matirx getbit(){ matirx x; for(int i=0;i<ac.tot;++i) { for(int j=0;j<4;++j) { if(!ac.end[ac.next[i][j]]) { x.mu[i][ac.next[i][j]]++; } } } return x;}char s[100500];int main(){ int n; ll m; while(scanf("%d%I64d",&n,&m)!=EOF) { ac.init(); for(int i=0;i<n;++i) { scanf("%s",s); ac.push(s); } ac.build(); matirx bit = getbit(); matirx ans = pow(bit,m); ll sum=0; for(int i=0;i<ac.tot;++i) { sum = (sum+ans.mu[0][i])%mod; } printf("%lld\n",sum); } return 0;}
HDU 2852
做法:AC自动机 + 状压dp
AC自动机上维护状态转移,对每个key进行表号,并用s表示,注意如果fail链指向标记也要进行标记
#include <bits/stdc++.h>using namespace std;int n,m,k;int num[1<<12];int dp[30][105][1<<12];const int mod=20090717;struct tire{ int next[105][26] , end[105] ,fail[105]; int tot,root; int newnode() { for(int i=0;i<26;++i) next[tot][i]=-1; end[tot++]=0; return tot-1; } void init() { tot=0; root = newnode(); } void pusuh(char s[],int cnt) { int len=strlen(s); int now=root; for(int i=0;i<len;++i) { if(next[now][s[i]-'a']==-1) next[now][s[i]-'a'] = newnode(); now = next[now][s[i]-'a']; } end[now]|=(1<<cnt); } void build() { fail[root]=root; queue<int> que; for(int i=0;i<26;++i) { if(next[root][i]==-1) next[root][i] = root; else { fail[next[root][i]] = root; que.push(next[root][i]); } } while(!que.empty()) { int now=que.front(); que.pop(); end[now]|=end[fail[now]]; for(int i=0;i<26;++i) { if(next[now][i]==-1) { next[now][i]=next[fail[now]][i]; } else { fail[next[now][i]] = next[fail[now]][i]; que.push(next[now][i]); } } } } int work() { for(int i=0;i<=n;++i) { for(int j=0;j<tot;++j) { for(int k=0;k<(1<<m);++k) { dp[i][j][k]=0; } } } dp[0][0][0]=1; for(int i=0;i<n;++i) { for(int j=0;j<tot;++j) { for(int k=0;k<(1<<m);++k) { if(!dp[i][j][k]) continue; for(int t=0;t<26;++t) { dp[i+1][next[j][t]][k|end[next[j][t]]] = ( dp[i+1][next[j][t]][k|end[next[j][t]]]+dp[i][j][k] )%mod; } } } } int ans=0; for(int i=0;i<(1<<m);++i) { if(num[i]<k) continue; for(int j=0;j<tot;++j) ans= (ans+dp[n][j][i])%mod; } return ans; }}ac;char s[105];int main(){ memset(num,0,sizeof(num)); for(int i=0;i<(1<<10);++i) { for(int j=0;j<10;++j) { if(i&(1<<j)) num[i]++; } } while(scanf("%d%d%d",&n,&m,&k)!=EOF) { if(n==0&&m==0&&k==0) break; ac.init(); for(int i=0;i<m;++i) { scanf("%s",s); ac.pusuh(s,i); } ac.build(); printf("%d\n",ac.work()); } return 0;}
HDU 2774
做法:后缀数组:将两个串放在一起,然后在中间加一个标记即可。答案就在 rank排名的交界处 ,一定要满足两个sa在不同的串内, 然后求最大的height
#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;const int maxn=5e5+10;char s1[maxn],s2[maxn],s[maxn<<1];int sa[maxn],t1[maxn],t2[maxn],c[maxn<<1];int rk[maxn],height[maxn];void getsa(int n,int m){ int *x=t1,*y=t2; for(int i=0;i<m;++i) c[i]=0; for(int i=0;i<n;++i) c[x[i]=s[i]]++; for(int i=1;i<m;++i) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(int i=n-k;i<n;++i) y[p++]=i; for(int i=0;i<n;++i) if(sa[i]>=k) y[p++] = sa[i]-k; for(int i=0;i<m;++i) c[i]=0; for(int i=0;i<n;++i) c[x[y[i]]]++; for(int i=1;i<m;++i) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for(int i=1;i<n;++i) x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n) break; m=p; }}void gethight(int n){ int k=0; for(int i=0;i<n;++i) rk[sa[i]]=i; for(int i=0;i<n;++i) { if(k) k--; else k=0; int j=sa[rk[i]-1]; while(s[i+k]==s[j+k]) k++; height[rk[i]]=k; }}int main(){ while(scanf("%s%s",s1,s2)!=EOF) { int pos=0; for(int i=0;s1[i];++i) s[pos++] = s1[i]-'a'+1; s[pos++]=28; for(int i=0;s2[i];++i) s[pos++] = s2[i]-'a'+1; s[pos++]=0; getsa(pos,29); gethight(pos); int ans=0, len = strlen(s1); for(int i=2;s[i];++i) { if(height[i]>ans) { if(sa[i-1]>=0 &&sa[i-1]<len&&len<sa[i]) ans=height[i]; if(0<=sa[i] && sa[i]<len &&len<sa[i-1]) ans=height[i]; } } printf("%d\n",ans); } return 0;}
POJ 3261
求重复k次以上的最长重复子串
做法:套完板子之后,二分答案,将heigh大于mid的分为一组如果有超过k个则检验成功
板子使用注意一些地方
getsa(n+1,maxn+2);
m基数取比最大的数稍大即可。最后串加个s[N]=0; hight是从2开始的!!!
#include <iostream>#include <cstring>#include <cstdio>#include <queue>using namespace std;const int maxn=20010;int s[maxn<<1];int sa[maxn],t1[maxn],t2[maxn],c[maxn<<1];int rk[maxn],height[maxn];void getsa(int n,int m){ int *x=t1,*y=t2; for(int i=0;i<m;++i) c[i]=0; for(int i=0;i<n;++i) c[x[i]=s[i]]++; for(int i=1;i<m;++i) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for(int k=1;k<=n;k<<=1) { int p=0; for(int i=n-k;i<n;++i) y[p++]=i; for(int i=0;i<n;++i) if(sa[i]>=k) y[p++] = sa[i]-k; for(int i=0;i<m;++i) c[i]=0; for(int i=0;i<n;++i) c[x[y[i]]]++; for(int i=1;i<m;++i) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for(int i=1;i<n;++i) x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++; if(p>=n) break; m=p; }}void gethight(int n){ int k=0,j; for(int i=0;i<=n;++i) rk[sa[i]]=i; for(int i=0;i<n;++i) { if(k) k--; j=sa[rk[i]-1]; while(s[i+k]==s[j+k]) k++; height[rk[i]]=k; }}bool judge(int mid,int n,int kk){ int num=1; for(int i=2;i<=n;++i) { if(height[i]>=mid) { num++; if(num>=kk) return 1; } else num=1; } return 0;}int main(){ int n,kk; while(scanf("%d%d",&n,&kk)!=EOF) { int maxn=0; for(int i=0;i<n;++i) { scanf("%d",&s[i]); maxn=max(maxn,s[i]);} s[n]=0; getsa(n+1,maxn+2); gethight(n); int l=0,r=n; int ans=0; while(l<=r) { int mid=(l+r)>>1; if(judge(mid,n,kk)) {ans = max(ans,mid); l=mid+1;} else r=mid-1; } printf("%d\n",ans); } return 0;}
阅读全文
0 0
- 2017 暑假艾教集训 day10 AC自动机+马拉车+后缀数组 +kmp
- 字符串 KMP Trie AC自动机 后缀数组
- 字符串模板 KMP AC自动机 Manacher 后缀数组
- 2017暑假七林集训day10
- 2017 暑假艾教集训 day10 (补zoj2112带修改的第k大)整体二分
- hdu6138 多校2017 ac自动机or后缀数组
- manacher 后缀数组 AC自动机 回文自动机 知识点讲解 课件
- hdu 4622 Reincarnation(后缀数组|后缀自动机|KMP)
- 2017 暑假艾教集训 day1
- 2017 暑假艾教集训 day2
- 2017 暑假艾教集训 day3
- 2017 暑假艾教集训 day4
- 2017 暑假艾教集训 day5
- 2017 暑假艾教集训 day6
- KMP算法 AC自动机
- KMP && AC自动机模板
- HDU3065 病毒侵袭持续中(AC自动机或后缀数组)
- [AC自动机 fail树 || 后缀数组] BZOJ 3172 [Tjoi2013]单词
- c++ 中 operator 使用小结
- Jfinal 第一天 idea中新建项目
- 常见锁原理和使用-旋转锁和SRWLock
- java使用jbarcode生成条形码2-2
- python中的进程池Pool
- 2017 暑假艾教集训 day10 AC自动机+马拉车+后缀数组 +kmp
- 信息论实验-信源编码算法 (Huffman and Shannonn Fano编码C++实现)
- 旧版本SSL/TLS将被弃用,如何应对?
- c# 线程操作控件
- Consul文档简要整理
- Python编程中NotImplementedError的使用
- malloc、calloc、realloc、free
- 神经机器翻译(Neural Machine Translation)系列教程
- 详解equals()方法和hashCode()方法