HDU 2825 AC自动机+状压DP

来源:互联网 发布:upchina是什么软件 编辑:程序博客网 时间:2024/06/07 00:32

题意

给M个字符串,要求组成一个长度为N的字符串,至少包含K个给定字符串。

题解

利用AC自动机,我们可以进行状态转移, 以及模板匹配。要求目标串长度为N,且包含K个给定字符串。所以可以在包含给定字符串的AC自动机上进行状态转移。
dp[i+1][u][last[u]|s]=(dp[i+1][u][last[u]|s]+dp[i][j][s])%MOD;
dp[i][j][k]表示,第i步,在j节点,已经包含的字符串状态为k。针对每一个在条件范围内的i,j,k都可以进行状态转移。最后统计一下i==n时包含字符串状态对应的字符串个数大于K的状态之和即为所求。

代码

#include <iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<string>#include<set>#include<map>#include<bitset>#include<stack>#define UP(i,l,h) for(int i=l;i<h;i++)#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)#define W(a) while(a)#define MEM(a,b) memset(a,b,sizeof(a))#define INF 0x3f3f3f3f3f3f3f3f#define LL long long#define ULL unsigned long long#define MAXN 10000#define EPS 1e-10#define MOD 20090717#define N 26using namespace std;int n,m,k;int ch[110][26];char st[15];int sz,num;int val[110],hasnum[1050],f[110],last[110];int dp[30][110][1050];void insert() {    int len=strlen(st);    int u=0;    UP(i,0,len) {        int x=st[i]-'a';        if(!ch[u][x]) {            val[sz]=0;            ch[u][x]=sz++;        }        u=ch[u][x];    }    val[u]=1<<num;}void cal() {    UP(i,0,1<<10) {        int j=i;        W(j) {            if(j%2==1)                hasnum[i]++;            j/=2;        }    }}void getFail() {    MEM(f,0);    MEM(last,0);    queue<int> q;    UP(i,0,26) {        if(ch[0][i]) {            q.push(ch[0][i]);            last[ch[0][i]]=val[ch[0][i]];        }    }    W(!q.empty()) {        int r=q.front();        q.pop();        UP(i,0,26) {            int u=ch[r][i];            if(!u) {                ch[r][i]=ch[f[r]][i];                continue;            }            q.push(u);            int v=f[r];            f[u]=ch[v][i];//            cout<<val[u]<<endl;            last[u]=(last[f[u]]|val[u]);        }    }}int main() {    cal();    W(~scanf("%d%d%d",&n,&m,&k)) {        if(n+m+k==0)            break;        MEM(val,0);        MEM(ch,0);        MEM(dp,0);        sz=1;        num=0;        UP(i,0,m) {            scanf("%s",st);            insert();            num++;        }        getFail();        dp[0][0][0]=1;        UP(i,0,n) {            UP(j,0,sz) {                UP(s,0,1<<m) {                    if(dp[i][j][s]==0)                        continue;                    UP(k,0,26) {                        int u=ch[j][k];                        dp[i+1][u][last[u]|s]=(dp[i+1][u][last[u]|s]+dp[i][j][s])%MOD;                    }                }            }        }        int ans=0;        UP(i,0,sz) {            UP(j,0,1<<m) {                if(hasnum[j]>=k) {                    ans=(ans+dp[n][i][j])%MOD;                }            }        }        printf("%d\n",ans);    }}/*2 2 1abcbcd1 1 1a*/
原创粉丝点击