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指针指向下一个后缀相同的串,复杂度是 O(n)

#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[u]=edge(v,u) eixsitdp[v]

然后通过快速幂加速这个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

dp[i][j] 表示第 i 个结点状态为 j 时的数量,然后转移就行。。。

#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个字母,可以考虑根据每种字母的数量将其哈希成一种状态。状态数最大是 114=14641 。然后dp就行了。

#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

首先求出各个资源串末尾之间的距离,要求不能有病毒串,所以走向病毒串的边不能走。因为各边为 1 ,因此跑一遍 bfs 就行了。然后作一遍状压dp,dp[i][j] 表示状态为 j ,且最后遇到的串是 j 时的消耗的最小字母数。

#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,dp[i][j][a][s] 表示第 i 个字母匹配到了自动机上第 j 个结点,消耗了 aR ,状态为 s 时的方案数。

#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找最短路。

dp[i][j] 表示第 i 个点在自动机上是第 j 个点的最小路径,只能向合法路径且点标号大的方向转移。因为从1开始,初始时将 dp[i][nxt[root][i]]=0

#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;}
原创粉丝点击