AC自动机题集
来源:互联网 发布:他改变了中国淘宝评论 编辑:程序博客网 时间:2024/06/04 18:14
AC自动机就是一种在 Trie树上的kmp,用于多模式串的匹配及对多模式串限制的dp。初始时将所有模式串放进Trie树中,然后在Trie树上构建next数组和fail数组。通过next可以进行转移,通过fail可以找到所有具有相同后缀的模式串。有了next数组,Trie树可以看成一个图。在这个图上可以进行各种dp,一般题目上规定了有很多字符串的限制的时候,应该就要想到AC自动机。
HDU-2222
复习AC自动机。
AC自动机是将多个模式串构建成一颗Trie,然后再Trie上构建fail指针。fail指针指向下一个后缀相同的串,复杂度是
#include<bits/stdc++.h>using namespace std;struct Trie{ int L,root,nxt[500007][26],end[500007],fail[500007]; int newnode() { for(int i=0;i<26;++i) nxt[L][i]=-1; end[L]=0; return L++; } void init() { L=0; root=newnode(); } void insert(char buf[]) { int len=strlen(buf); int now=root; for(int i=0;i<len;++i) { if(nxt[now][buf[i]-'a']==-1) nxt[now][buf[i]-'a']=newnode(); now=nxt[now][buf[i]-'a']; } ++end[now]; } void build() { queue<int> q; fail[root]=root; for(int i=0;i<26;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front(); q.pop(); for(int i=0;i<26;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } int query(char buf[]) { int len=strlen(buf); int tmp,now=root,res=0; for(int i=0;i<len;++i) { now=nxt[now][buf[i]-'a']; tmp=now; while(tmp!=root) { res+=end[tmp]; end[tmp]=0; tmp=fail[tmp]; } } return res; }};Trie t;char s[1000007];char pt[57];int main(){ int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); t.init(); for(int i=0;i<n;++i) { scanf("%s",pt); t.insert(pt); } t.build(); scanf("%s",s); printf("%d\n",t.query(s)); } return 0;}
HDU - 2896
set
维护不同的编号
#include<bits/stdc++.h>using namespace std;struct Trie{ int nxt[100007][128],L,root,fail[100007],end[100007]; int newnode() { for(int i=0;i<128;++i) nxt[L][i]=-1; end[L]=0; return L++; } void init() { L=0; root=newnode(); } void insert(char buf[],int id) { int len=strlen(buf); int now=root; for(int i=0;i<len;++i) { if(nxt[now][buf[i]]==-1) nxt[now][buf[i]]=newnode(); now=nxt[now][buf[i]]; } end[now]=id; } void build() { queue<int> q; for(int i=0;i<128;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); for(int i=0;i<128;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } set<int> query(char buf[]) { int len=strlen(buf); int now=root,tmp; set<int> res; for(int i=0;i<len;++i) { now=nxt[now][buf[i]]; tmp=now; while(tmp!=root) { if(end[tmp]) res.insert(end[tmp]); tmp=fail[tmp]; } } return res; }};Trie t;char pt[207];char s[10007];int main(){ int n; while(~scanf("%d",&n)) { t.init(); for(int i=1;i<=n;++i) { scanf("%s",pt); t.insert(pt,i); } t.build(); int m,ans=0; scanf("%d",&m); for(int i=1;i<=m;++i) { scanf("%s",s); auto res=t.query(s); if(res.size()) { ++ans; printf("web %d:",i); for(auto k : res) printf(" %d",k); puts(""); } } printf("total: %d\n",ans); } return 0;}
HDU-3065
计数。。
#include<bits/stdc++.h>using namespace std;int cnt[1007];struct Trie{ int L,root,nxt[50007][128],fail[50007],end[50007]; int newnode() { for(int i=0;i<128;++i) nxt[L][i]=-1; end[L]=0; return L++; } void init() { L=0; root=newnode(); } void insert(string & buf , int id) { int now=root,len=buf.length(); for(int i=0;i<len;++i) { if(nxt[now][buf[i]]==-1) nxt[now][buf[i]]=newnode(); now=nxt[now][buf[i]]; } end[now]=id; } void build() { queue<int> q; for(int i=0;i<128;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); for(int i=0;i<128;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } void query(string & buf) { int len=buf.length(),now=root,tmp; for(int i=0;i<len;++i) { now=nxt[now][buf[i]]; tmp=now; while(tmp!=root) { ++cnt[end[tmp]]; tmp=fail[tmp]; } } }};string pt[1007],s;Trie t;int main (){ ios::sync_with_stdio(false); int n; while(cin >> n) { t.init(); memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;++i) { cin >> pt[i]; t.insert(pt[i],i); } t.build(); cin >> s; t.query(s); for(int i=1;i<=n;++i) if(cnt[i]) cout << pt[i] << ": " << cnt[i] << '\n'; } return 0;}
ZOJ - 3430
先base64解码后再搞。。有个RE点就是解码后的字符是uchar的。
#include<bits/stdc++.h>using namespace std;string b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";int f[128];int buf[100000];int str[100000],strl;void decode(string &s){ int len=0; for(int i=0;i<s.length();++i) { if(s[i]=='=') { len-=(s.length()-i+1)*2; break; } for(int j=0;j<6;++j) buf[len+j]=(f[s[i]]>>(6-j-1))&1; len+=6; } strl=0; for(int i=0;i<len;i+=8) { int k=0; for(int j=0;j<8;++j) k<<=1,k|=buf[i+j]; str[strl++]=k; }}struct Trie{ int L,root,nxt[40000][256],fail[40000],end[40000],vis[40000]; int newnode() { for(int i=0;i<256;++i) nxt[L][i]=-1; end[L]=vis[L]=0; return L++; } void init() { L=0; root=newnode(); } void insert(int buf[],int len) { int now=root; for(int i=0;i<len;++i) { if(nxt[now][buf[i]]==-1) nxt[now][buf[i]]=newnode(); now=nxt[now][buf[i]]; } ++end[now]; } void build() { queue<int> q; for(int i=0;i<256;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); for(int i=0;i<256;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } int query(int buf[],int len ,int id) { int now=root,tmp,res=0; for(int i=0;i<len;++i) { now=nxt[now][buf[i]]; tmp=now; while(tmp!=root) { if(vis[tmp]!=id) res+=end[tmp]; vis[tmp]=id; tmp=fail[tmp]; } } return res; }};Trie t;int main(){// ios::sync_with_stdio(false); for(int i=0;i<64;++i) f[b64[i]]=i; int n,m; while(cin >> n ) { string s; t.init(); for(int i=1;i<=n;++i) { cin >> s; decode(s); t.insert(str,strl); } t.build(); cin >> m; for(int i=1;i<=m;++i) { cin >> s; decode(s); cout << t.query(str,strl,i) << '\n'; } cout << '\n'; } return 0;}
POJ - 2778
考虑将所有串建AC自动机,然后Trie树上的next代表邻接表。
如果该点的end
不是1,即不是某个串的终止点,那么这个点是可以被转移的,转移方程为
然后通过快速幂加速这个dp就行了。
#include<cstdio>#include<cstring>#include<queue>using namespace std;typedef long long ll;const ll mod = 100000;struct Matrix{ ll a[57][57]; int n; Matrix(int _n) { n=_n; memset(a,0,sizeof(a)); } ll* operator [](int index) { return a[index]; } Matrix operator * (Matrix &b) { Matrix c(n); for(int i=0;i<n;++i) for(int k=0;k<n;++k) if(a[i][k]) for(int j=0;j<n;++j) c[i][j]=(c[i][j]+a[i][k]*b[k][j])%mod; return c; }};Matrix powm(Matrix a, int b){ Matrix c(a.n); for(int i=0;i<a.n;++i) for(int j=0;j<a.n;++j) c[i][j]=(i==j); while(b) { if(b&1) c=c*a; a=a*a; b>>=1; } return c;}struct Trie{ int nxt[57][4],fail[57],end[57],L,root; int newnode() { for(int i=0;i<4;++i) nxt[L][i]=-1; end[L]=0; return L++; } void init() { L=0; root=newnode(); } int f(char ch) { if(ch=='A') return 0; else if(ch=='C') return 1; else if(ch=='G') return 2; else if(ch=='T') return 3; } void insert(char buf[]) { int len=strlen(buf),now=root; for(int i=0;i<len;++i) { if(nxt[now][f(buf[i])]==-1) nxt[now][f(buf[i])]=newnode(); now=nxt[now][f(buf[i])]; } end[now]=1; } void build() { queue<int> q; for(int i=0;i<4;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); if(end[fail[now]]) end[now]=1; for(int i=0;i<4;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } ll query(int b) { Matrix a(L); for(int i=0;i<L;++i) for(int j=0;j<4;++j) if(!end[nxt[i][j]]) ++a[nxt[i][j]][i]; a=powm(a,b); ll res=0; for(int i=0;i<L;++i) res=(res+a[i][0])%mod; return res; }}t;char pt[50];int main (){ int n,m; while(~scanf("%d%d",&n,&m)) { t.init(); for(int i=0;i<n;++i) { scanf("%s",pt); t.insert(pt); } t.build(); printf("%I64d\n",t.query(m)); } return 0;}
HDU - 2243
快速幂的时候再维护一个求和变量就行了。。其他跟上题差不多。
#include<bits/stdc++.h>using namespace std;typedef unsigned long long ll;struct Matrix{ ll a[57][57]; int n; Matrix(int _n) { n=_n; for(int i=0;i<n;++i) for(int j=0;j<n;++j) a[i][j]=0; } ll* operator [](int index) { return a[index]; } Matrix operator * (Matrix &b) { Matrix c(n); for(int i=0;i<n;++i) for(int k=0;k<n;++k) if(a[i][k]) for(int j=0;j<n;++j) c[i][j]=c[i][j]+a[i][k]*b[k][j]; return c; }};Matrix powm(Matrix &a, ll b){ Matrix c(a.n); for(int i=0;i<a.n;++i) for(int j=0;j<a.n;++j) c[i][j]=(i==j); while(b) { if(b&1) c=c*a; a=a*a; b>>=1; } return c;}struct Trie{ int nxt[57][26],fail[57],end[57],L,root; int newnode() { for(int i=0;i<26;++i) nxt[L][i]=-1; end[L]=0; return L++; } void init() { L=0; root=newnode(); } void insert(char buf[]) { int len=strlen(buf),now=root; for(int i=0;i<len;++i) { if(nxt[now][buf[i]-'a']==-1) nxt[now][buf[i]-'a']=newnode(); now=nxt[now][buf[i]-'a']; } end[now]=1; } void build() { queue<int> q; for(int i=0;i<26;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); if(end[fail[now]]) end[now]=1; for(int i=0;i<26;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } ll query(ll b) { Matrix a(L+1); for(int i=0;i<L;++i) for(int j=0;j<26;++j) if(!end[nxt[i][j]]) ++a[nxt[i][j]][i]; for(int i=0;i<=L;++i) a[L][i]=1; a=powm(a,b+1); return a[L][0]-1; }}t;char pt[50];ll getAll(ll b){ Matrix c(2); c[0][0]=c[0][1]=1; c[1][1]=26; c=powm(c,b); return c[0][1]*26;}int main (){ int n;ll m; ios::sync_with_stdio(false); while(cin >> n >> m) { t.init(); for(int i=0;i<n;++i) { cin >> pt; t.insert(pt); } t.build(); cout << getAll(m)-t.query(m) << '\n'; } return 0;}
HDU - 2825
#include<bits/stdc++.h>using namespace std;const int mod = 20090717;struct Trie{ int nxt[107][26],end[107],L,root,fail[107],dp[107][1024],tmp[107][1024]; int newnode() { for(int i=0;i<26;++i) nxt[L][i]=-1; end[L]=0; return L++; } void init() { L=0; root=newnode(); } void insert(char buf[],int id) { int len=strlen(buf),now=root; for(int i=0;i<len;++i) { if(nxt[now][buf[i]-'a']==-1) nxt[now][buf[i]-'a'] = newnode(); now=nxt[now][buf[i]-'a']; } end[now]|=(1<<id); } void build() { queue<int> q; for(int i=0;i<26;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); end[now]|=end[fail[now]]; for(int i=0;i<26;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } int solve(int n,int m,int c) { for(int j=0;j<L;++j) for(int s=0;s<(1<<m);++s) dp[j][s]=0; dp[0][0]=1; for(int i=0;i<n;++i) { for(int j=0;j<L;++j) for(int s=0;s<(1<<m);++s) tmp[j][s]=0; for(int j=0;j<L;++j) for(int s=0;s<(1<<m);++s) if(dp[j][s]) { for(int k=0;k<26;++k) { int nx=nxt[j][k]; tmp[nx][end[nx]|s]=(tmp[nx][end[nx]|s]+dp[j][s])%mod; } } for(int j=0;j<L;++j) for(int s=0;s<(1<<m);++s) dp[j][s]=tmp[j][s]; } int res=0; for(int i=0;i<L;++i) for(int j=0;j<(1<<m);++j) if(__builtin_popcount(j)>=c) res=(res+dp[i][j])%mod; return res; }}t;char buf[20];int main(){ int n,m,k; while(~scanf("%d%d%d",&n,&m,&k)) { if(n==0&&m==0&&k==0) break; t.init(); for(int i=0;i<m;++i) { scanf("%s",buf); t.insert(buf,i); } t.build(); printf("%d\n",t.solve(n,m,k)); } return 0;}
ZOJ - 3228
AC自动机常见的计数字符串题,不过有不能重叠的限制。可以考虑维护每种模式串上一次出现的位置 last
,若当前位置减上一次出现位置大于等于长度的话,这部分可以计数。
#include<bits/stdc++.h>using namespace std;const int N=1e5+7;map<string,int> mp;string s;int id[N],len[N],last[N],c1[N],c2[N],op[N];struct Trie{ int L,root,nxt[N*6][26],fail[N*6],end[N*6]; int newnode() { for(int i=0;i<26;++i) nxt[L][i]=-1; end[L]=0; return L++; } void init() { L=0; root=newnode(); } void insert(string & buf, int id) { int now=root; for(int i=0;i<buf.length();++i) { if(nxt[now][buf[i]-'a']==-1) nxt[now][buf[i]-'a']=newnode(); now = nxt[now][buf[i]-'a']; } end[now]=id; } void build() { queue<int> q; for(int i=0;i<26;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); for(int i=0;i<26;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } void query(string &buf) { int now=root,tmp; for(int i=0;i<buf.length();++i) { now=nxt[now][buf[i]-'a']; tmp=now; while(tmp!=root) { if(end[tmp]) { if(i-last[end[tmp]]>=len[end[tmp]]) ++c2[end[tmp]],last[end[tmp]]=i; ++c1[end[tmp]]; } tmp=fail[tmp]; } } }}t;int main(){ ios::sync_with_stdio(false); int kase=1; string buf; while(cin >> s) { int n,cur=0; cin >> n; mp.clear(); t.init(); for(int i=0;i<n;++i) { cin >> op[i] >> buf; if(!mp.count(buf)) { mp[buf]=++cur; len[cur]=buf.length(); last[cur]=-10000; c1[cur]=c2[cur]=0; t.insert(buf,cur); } id[i]=mp[buf]; } t.build(); t.query(s); cout << "Case " << (kase++) << '\n'; for(int i=0;i<n;++i) { if(op[i]) cout << c2[id[i]] << '\n'; else cout << c1[id[i]] << '\n'; } cout << '\n' ; } return 0;}
HDU - 3341
假如只有A和C这两个字母的话,那么很简单,直接状压转移就行,不过这里有4个字母,可以考虑根据每种字母的数量将其哈希成一种状态。状态数最大是
#include<bits/stdc++.h>using namespace std;int hs[41][41][41][41],dp[507][15000];inline int Max(int a,int b) { return a > b ? a : b; }struct Trie{ int L,root,nxt[507][4],fail[507],end[507]; int newnode() { for(int i=0;i<4;++i) nxt[L][i]=-1; end[L]=0; return L++; } void init() { L=0; root=newnode(); } int f(char ch) { if(ch=='A') return 0; else if(ch=='G') return 1; else if(ch=='C') return 2; else return 3; } void insert(char buf[]) { int now=root,len=strlen(buf); for(int i=0;i<len;++i) { if(nxt[now][f(buf[i])]==-1) nxt[now][f(buf[i])]=newnode(); now = nxt[now][f(buf[i])]; } ++end[now]; } void build() { queue<int> q; for(int i=0;i<4;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); end[now]+=end[fail[now]]; for(int i=0;i<4;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } int query(char buf[]) { int cnt[4],len=strlen(buf); memset(cnt,0,sizeof(cnt)); for(int i=0;i<len;++i) ++cnt[f(buf[i])]; int all=0; for(int a=0;a<=cnt[0];++a) for(int b=0;b<=cnt[1];++b) for(int c=0;c<=cnt[2];++c) for(int d=0;d<=cnt[3];++d) hs[a][b][c][d]=all++; for(int i=0;i<L;++i) for(int j=0;j<all;++j) dp[i][j]=-1; dp[0][0]=1; for(int a=0;a<=cnt[0];++a) for(int b=0;b<=cnt[1];++b) for(int c=0;c<=cnt[2];++c) for(int d=0;d<=cnt[3];++d) for(int i=0;i<L;++i) if(dp[i][hs[a][b][c][d]]!=-1) { int id=hs[a][b][c][d]; if(a+1<=cnt[0]) dp[nxt[i][0]][hs[a+1][b][c][d]]=Max(dp[nxt[i][0]][hs[a+1][b][c][d]],dp[i][id]+end[nxt[i][0]]); if(b+1<=cnt[1]) dp[nxt[i][1]][hs[a][b+1][c][d]]=Max(dp[nxt[i][1]][hs[a][b+1][c][d]],dp[i][id]+end[nxt[i][1]]); if(c+1<=cnt[2]) dp[nxt[i][2]][hs[a][b][c+1][d]]=Max(dp[nxt[i][2]][hs[a][b][c+1][d]],dp[i][id]+end[nxt[i][2]]); if(d+1<=cnt[3]) dp[nxt[i][3]][hs[a][b][c][d+1]]=Max(dp[nxt[i][3]][hs[a][b][c][d+1]],dp[i][id]+end[nxt[i][3]]); } int res=0; for(int i=0;i<L;++i) res=Max(res,dp[i][all-1]); return res-1; }}t;char buf[50];int main (){ int n,kase=1; while(~scanf("%d",&n)) { if(n==0) break; t.init(); for(int i=0;i<n;++i) { scanf("%s",buf); t.insert(buf); } t.build(); scanf("%s",buf); printf("Case %d: %d\n",kase++,t.query(buf)); } return 0;}
HDU - 3247
首先求出各个资源串末尾之间的距离,要求不能有病毒串,所以走向病毒串的边不能走。因为各边为 bfs
就行了。然后作一遍状压dp,
#include<bits/stdc++.h>using namespace std;const int N=60007,INF=0x3f3f3f3f;int d[10][10],dis[N],tail[10];int Q[N];struct Queue{ int head,tail; Queue() : head(0) , tail(0) {} bool empty(){return head==tail;} void push(int a){Q[tail++]=a;} void pop() { ++head; } int front() { return Q[head]; }};struct Trie{ int nxt[N][2],fail[N],end[N],rs[N],L,root,n; bool vis[N]; int newnode() { nxt[L][0]=nxt[L][1]=-1; end[L]=0; rs[L]=0; return L++; } void init() { L=0; root=newnode(); } void insert_rs(char buf[],int id) { int now=root,len=strlen(buf); for(int i=0;i<len;++i) { if(nxt[now][buf[i]-'0']==-1) nxt[now][buf[i]-'0']=newnode(); now=nxt[now][buf[i]-'0']; } rs[now]|=(1<<id); tail[id]=now; } void insert(char buf[]) { int now=root,len=strlen(buf); for(int i=0;i<len;++i) { if(nxt[now][buf[i]-'0']==-1) nxt[now][buf[i]-'0']=newnode(); now=nxt[now][buf[i]-'0']; } end[now]=1; } void build() { Queue q; for(int i=0;i<2;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); rs[now]|=rs[fail[now]]; end[now]|=end[fail[now]]; for(int i=0;i<2;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } vector<int> tmp; vector<int> & pts(int k) { tmp.clear(); for(int i=0;i<n;++i) if((k>>i)&1) tmp.push_back(i); return tmp; } void bfs(int st,int d[]) {// puts("bfs"); Queue q; for(int i=0;i<n;++i) d[i]=0x3f3f3f3f; memset(vis,0,sizeof(vis)); memset(dis,0x3f,sizeof(dis)); dis[st]=0; for(int v : pts(rs[st])) d[v]=0; vis[st]=true; q.push(st); while(!q.empty()) { int p=q.front();q.pop(); int u=nxt[p][0]; if(!end[u]&&!vis[u]) { vis[u]=true; dis[u]=dis[p]+1; q.push(u); if(rs[u]) for(int v : pts(rs[u])) d[v]=min(dis[u],d[v]); } u=nxt[p][1]; if(!end[u]&&!vis[u]) { vis[u]=true; dis[u]=dis[p]+1; q.push(u); if(rs[u]) for(int v : pts(rs[u])) d[v]=min(dis[u],d[v]); } } }}t;char buf[50007];int dp[10][1024];int main(){ int n,m; while(~scanf("%d%d",&n,&m)) { if(n==0 || m==0) break; t.init(); t.n=n; memset(dp,0x3f,sizeof(dp)); for(int i=0;i<n;++i) { scanf("%s",buf); t.insert_rs(buf,i); dp[i][1<<i]=strlen(buf); } for(int i=0;i<m;++i) { scanf("%s",buf); t.insert(buf); } t.build(); for(int i=0;i<n;++i) t.bfs(tail[i],d[i]); for(int i=1;i<(1<<n);++i) for(int j=0;j<n;++j) for(int k=0;k<n;++k) if(((i>>k)&1)^1) dp[k][i|(1<<k)]=min(dp[k][i|(1<<k)],dp[j][i]+d[j][k]); int ans=INF; for(int i=0;i<n;++i) ans=min(ans,dp[i][(1<<n)-1]); printf("%d\n",ans); } return 0;}
HDU - 4758
AC自动机上dp,
#include<bits/stdc++.h>using namespace std;const int mod = 1e9+7;int Q[207];struct Queue{ int head,tail; Queue() : head(0) , tail(0) {} bool empty(){return head==tail;} void push(int a){Q[tail++]=a;} void pop() { ++head; } int front() { return Q[head]; }};struct Trie{ int nxt[207][2],end[207],fail[207],dp[203][203][103][4],root,L; int newnode() { nxt[L][0]=nxt[L][1]=-1; end[L]=0; return L++; } void init() { L=0; root=newnode(); } int f(char ch){ return ch=='R' ? 0 : 1; } void insert(char buf[],int id) { int now=root,len=strlen(buf); for(int i=0;i<len;++i) { if(nxt[now][f(buf[i])]==-1) nxt[now][f(buf[i])]=newnode(); now=nxt[now][f(buf[i])]; } end[now]=(1<<id); } void build() { Queue q; for(int i=0;i<2;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); end[now]|=end[fail[now]]; for(int i=0;i<2;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } int query(int n,int m) { int i,j,a,s; for(i=0;i<=n+m;++i) for(j=0;j<L;++j) for(a=0;a<=n;++a) for(s=0;s<4;++s) dp[i][j][a][s]=0; dp[0][0][0][0]=1; for(i=1;i<=n+m;++i) for(j=0;j<L;++j) for(a=0;a<=n&&a<i;++a) for(s=0;s<4;++s) { int nx=nxt[j][0]; if(a<n) dp[i][nx][a+1][s|end[nx]]=(dp[i][nx][a+1][s|end[nx]]+dp[i-1][j][a][s])%mod; nx=nxt[j][1]; if(i-1-a<m) dp[i][nx][a][s|end[nx]]=(dp[i][nx][a][s|end[nx]]+dp[i-1][j][a][s])%mod; } int ans=0; for(i=0;i<L;++i) ans=(ans+dp[n+m][i][n][3])%mod; return ans; }}t;int main (){ int T,n,m; scanf("%d",&T); char buf[207]; while(T--) { int n,m; scanf("%d%d",&n,&m); t.init(); scanf("%s",buf); t.insert(buf,0); scanf("%s",buf); t.insert(buf,1); t.build(); printf("%d\n",t.query(n,m)); } return 0;}
HDU - 4511
在AC自动机上dp找最短路。
#include<bits/stdc++.h>using namespace std;typedef double ld;const ld INF = 1e20;ld x[51],y[51],d[51][51];struct Trie{ int nxt[507][51],fail[507],end[507],L,root,n; ld dp[51][507]; int newnode() { for(int i=1;i<=n;++i) nxt[L][i]=-1; end[L]=0; return L++; } void init(int _n) { n=_n; L=0; root=newnode(); } void insert(int buf[],int len) { int now=root; for(int i=0;i<len;++i) { if(nxt[now][buf[i]]==-1) nxt[now][buf[i]]=newnode(); now=nxt[now][buf[i]]; } end[now]=1; } void build() { queue<int> q; for(int i=1;i<=n;++i) { if(nxt[root][i]==-1) nxt[root][i]=root; else { fail[nxt[root][i]]=root; q.push(nxt[root][i]); } } while(!q.empty()) { int now=q.front();q.pop(); end[now]|=end[fail[now]]; for(int i=1;i<=n;++i) { if(nxt[now][i]==-1) nxt[now][i]=nxt[fail[now]][i]; else { fail[nxt[now][i]]=nxt[fail[now]][i]; q.push(nxt[now][i]); } } } } ld query() { for(int i=1;i<=n;++i) for(int j=i+1;j<=n;++j) d[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])); for(int i=1;i<=n;++i) for(int j=0;j<L;++j) dp[i][j]=INF; dp[1][nxt[root][1]]=0; for(int i=1;i<=n;++i) for(int j=0;j<L;++j) if(dp[i][j]!=INF) for(int k=i+1;k<=n;++k) if(!end[nxt[j][k]]) dp[k][nxt[j][k]]=min(dp[k][nxt[j][k]],dp[i][j]+d[i][k]); ld ans = INF; for(int i=0;i<L;++i) ans=min(ans,dp[n][i]); return ans; }}t;int buf[51];int main (){ int n,m; while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0) break; for(int i=1;i<=n;++i) scanf("%lf%lf",&x[i],&y[i]); t.init(n); for(int i=0;i<m;++i) { int k; scanf("%d",&k); for(int i=0;i<k;++i) scanf("%d",&buf[i]); t.insert(buf,k); } t.build(); ld ans=t.query(); if(ans==INF) puts("Can not be reached!"); else printf("%.2f\n",ans); } return 0;}
- AC自动机题集
- AC自动机题集
- AC自动机练习解题题集
- AC自动机水题
- AC自动机的初步学习 hdu2222 AC自动机入门题
- HDOJ2222 AC自动机模版题
- LA4670 AC自动机模版题
- hdu2222 ac自动机模板题
- HDU2222 AC自动机水题
- hdu2222 ac自动机裸题
- POJ2778 AC自动机经典题
- HDU2896,ac自动机模板题
- AC自动机...
- AC自动机
- AC 自动机
- AC自动机
- AC自动机
- ac自动机
- 600. Non-negative Integers without Consecutive Ones
- 划分树 图文讲解让你一次就懂 hdu2665为例
- 629. K Inverse Pairs Array
- iOS 镜像,旋转
- 物理引擎的空间数据结构
- AC自动机题集
- windows下安装scrapy
- 老妪能解PCA
- 565. Array Nesting
- UVA.1639 Candy (期望 高精度)
- 第十章 会话管理(二) 会话管理器
- 在Linux下创建7种类型的文件
- 给深度学习入门者的Python快速教程
- 为什么你应该(从现在开始就)写博客