Wireless Password HDU - 2825 AC自动机DP计数
给m个单词,问构造长为n且含有至少k个单词的串的种数
朴素的自动机上DP,遍历了自动机的所有状态,dp[i][j][k]:长为i的串匹配到状态j,出现k编码状态word的串的种数
#include<bits/stdc++.h> #include<stdio.h> #include<algorithm> #include<queue> #include<string.h> #include<iostream> #include<math.h> #include<set> #include<map> #include<vector> #include<iomanip> using namespace std; #define ll long long #define ull unsigned long long #define pb push_back #define FOR(a) for(int i=1;i<=a;i++) const int inf=0x3f3f3f3f; const int maxn=140+9; const int mod=20090717; const int sigma=26; int n,m,k; int dp[30][110][1<<10]; //dp[i][j][k]:长度为i的串匹配到状态j,出现了k状态word的串个数 int num[5005]; //num[i]:i有多少个二进制为1位 struct automata{ int ch[maxn][sigma]; int val[maxn]; int f[maxn]; int sz; int newnode(){ memset(ch[sz],0,sizeof(ch[sz])); f[sz]=val[sz]=0; return sz++; } void init(){ memset(val,0,sizeof(val)); sz=0; newnode(); } void insert(char *s,int v){ int u=0; int len=strlen(s); for(int i=0;i<len;i++){ int id=s[i]-'a';//s[i]-'a'; if(!ch[u][id])ch[u][id]=newnode(); u=ch[u][id]; } val[u]|=(1<<v); } void build(){ queue<int>q; q.push(0); while(!q.empty()){ int u=q.front();q.pop(); val[u]|=val[f[u]]; for(int i=0;i<sigma;i++){ int v=ch[u][i]; if(!v)ch[u][i]=ch[f[u]][i]; else q.push(v); if(u&&v)f[v]=ch[f[u]][i]; } } } int work(){ for(int i=0;i<=n;i++){ for(int j=0;j<sz;j++){ for(int p=0;p<(1<<m);p++){ dp[i][j][p]=0; } } } dp[0][0][0]=1; for(int i=0;i<n;i++){ for(int j=0;j<sz;j++){ for(int p=0;p<(1<<m);p++){ if(dp[i][j][p]>0){ for(int c=0;c<26;c++){ int nxti=i+1; int nxtj=ch[j][c]; int nxtp=(p|val[nxtj]); dp[nxti][nxtj][nxtp]+=dp[i][j][p]; dp[nxti][nxtj][nxtp]%=mod; } } } } } int ans=0; for(int p=0;p<(1<<m);p++){ if(num[p]<k)continue; //剪枝,至少有k个位 for(int i=0;i<sz;i++){ ans=(ans+dp[n][i][p])%mod; } } return ans; } }ac; char s[20]; int main(){ for(int i=0;i<(1<<10);i++){ num[i]=0; for(int j=0;j<10;j++){ if(i & (1<<j))num[i]++; } } while(~scanf("%d%d%d",&n,&m,&k)){ if(n==0 && m==0 && k==0)break; ac.init(); for(int i=0;i<m;i++){ scanf("%s",s); ac.insert(s,i); } ac.build(); printf("%d\n",ac.work()); } }