TC SRM 519 600pt

来源:互联网 发布:阿里云服务器能转让吗 编辑:程序博客网 时间:2024/05/01 06:42

自动机的DP


#include<cstdio>#include<cstring>#include<queue>#define MAXN 305#define ALP 26#define MOD 1000000009typedef long long ll;using namespace std;int n,m,k;char s[52];int next[MAXN][ALP],fail[MAXN],flag[MAXN],pos;int newnode(){    for(int i=0;i<ALP;i++)next[pos][i]=0;    fail[pos]=flag[pos]=0;    return pos++;}void insert(char *s,int id){    int p=0;    for(int i=0;s[i];i++){        int k=s[i]-'a',&x=next[p][k];        p=x?x:x=newnode();    }    flag[p]=1<<(id-1);}void makenext(){    queue<int>q;    q.push(0);    while(!q.empty()){        int u=q.front();        q.pop();        for(int i=0;i<ALP;i++){            int v=next[u][i];            if(v==0)next[u][i]=next[fail[u]][i];            else q.push(v);            if(u&&v){                fail[v]=next[fail[u]][i];                //这里注意合并状态                flag[v]|=flag[fail[v]];            }        }    }}ll d[2][MAXN][64];ll dp(){    int full=(1<<m),cur=0;    memset(d,0,sizeof(d));    d[0][0][0]=1;    for(int i=0;i<n;i++){        cur^=1;        for(int u=0;u<pos;u++){            for(int s=0;s<full;s++)                d[cur][u][s]=0;        }        for(int u=0;u<pos;u++){            for(int s=0;s<full;s++){                //如果这个状态还没有到达过                int bit=0;                for(int i=s;i;bit++,i-=(i&-i));                if(bit>k)continue;                if(d[cur^1][u][s]==0)continue;                //用这个状态跟新它的后继节点                for(int k=0;k<ALP;k++){                    int v=next[u][k];                    ll &x=d[cur][v][flag[v]|s];                    x=(x+d[cur^1][u][s])%MOD;                }            }        }    }    //统计第n步走过=k个单词的状态的总数    ll ans=0;    for(int s=0;s<full;s++){        int bit=0;        for(int i=s;i;bit++,i-=(i&-i));        if(bit!=k)continue;        for(int i=0;i<pos;i++)            ans=(ans+d[cur][i][s])%MOD;    }    return ans;}int main(){    while(scanf("%d%d%d",&n,&m,&k)){        pos=0;newnode();        for(int i=1;i<=m;i++){            scanf("%s",s);            insert(s,i);        }        makenext();        ll ans=dp();        printf("%lld\n",ans);    }    return 0;}


原创粉丝点击