Wireless Password HDU

来源:互联网 发布:sai软件详细介绍 编辑:程序博客网 时间:2024/06/03 12:41

给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());}}

原创粉丝点击