HDU-2825
题意:多组输入,每组给定n,m,k三个整数,一个长度为n的字符串,由m个子字符串中的至少k个组成,求一共有多少种排列组合方法,结果需要mod
解题思路:
ac自动机上跑状压DP
dp[i+1][nx][k|val[nx]] = (dp[i+1][nx][k|val[nx]]+dp[i][j][k])%mod
第一维表示当前主串长度,第二维表示自动机上的节点,第三维用二进制表示集合中存在哪几个字符串。需要利用辅助数组num预处理二进制下数字x的1的个数,即包含字符串的个数
代码:
//#pragma GCC optimize(3)
#include<iostream>
#include<algorithm>
#include<vector>
#include<deque>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<string>
#include<sstream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cctype>
#include<cassert>
#include<cstdlib>
#include<utility>
#include<iterator>
#include<iomanip>
using namespace std;
#define lowbit(x) x&(-x)
typedef long long ll;
typedef long double lb;
typedef unsigned long long ull;
int read();
const double PI = acos(-1.0);
const int maxn = 110;
const int mod = 20090717;
int n,m,cnt;
int tot;
struct node
{
int nx[26];
int val;
int fail;
}ac[maxn];
int num[1<<11];
int dp[30][maxn][1<<10];//长度,节点,状态
int ans;
char s[50];
void init()
{
tot = 0;
for(int i = 0;i<maxn;i++)
{
memset(ac[i].nx,0,sizeof(ac[i].nx));
ac[i].fail = 0;
ac[i].val = 0;
}
}
void getnum()
{
for(int i = 0;i<(1<<10);i++)
{
num[i] = 0;
for(int j = 0;j<10;j++)
{
if(i&(1<<j))
{
num[i]++;
}
}
}
}
void insert(char *s,int id)
{
int p = 0;
int len = strlen(s);
for(int i = 0; i<len; i++)
{
int ch = s[i]-'a';
if(!ac[p].nx[ch])
{
ac[p].nx[ch] = ++tot;
}
p = ac[p].nx[ch];
}
ac[p].val|=(1<<id);
}
void getfail()
{
queue<int> q;
for(int i = 0;i<26;i++)
{
if(ac[0].nx[i])
{
ac[ac[0].nx[i]].fail = 0;
q.push(ac[0].nx[i]);
}
}
while(!q.empty())
{
int r = q.front();
q.pop();
ac[r].val|=ac[ac[r].fail].val;
for(int i = 0;i<26;i++)
{
if(!ac[r].nx[i])
{
ac[r].nx[i] = ac[ac[r].fail].nx[i];
}else
{
ac[ac[r].nx[i]].fail = ac[ac[r].fail].nx[i];
q.push(ac[r].nx[i]);
}
}
}
}
int gao()
{
memset(dp,0,sizeof(dp));
dp[0][0][0] = 1;
for(int i = 0;i<n;i++){
for(int j = 0;j<=tot;j++){
for(int k = 0;k<(1<<m);k++){
if(dp[i][j][k])
{
for(int c = 0;c<26;c++)
{
int nowi = i+1;
int nowj = ac[j].nx[c];
int nowk = k|ac[nowj].val;
dp[nowi][nowj][nowk] += dp[i][j][k];
dp[nowi][nowj][nowk]%=mod;
}
}
}
}
}
ans = 0;
for(int i =0;i<(1<<m);i++)
{
if(num[i]>=cnt)
{
for(int j = 0;j<=tot;j++)
{
ans = (ans+dp[n][j][i])%mod;
}
}
}
return ans%mod;
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
getnum();
while(scanf("%d%d%d",&n,&m,&cnt)!=EOF)
{
if(n==0&&m==0&&cnt==0)break;
init();
for(int i = 0;i<m;i++)
{
scanf("%s",&s);
insert(s,i);
}
getfail();
printf("%d
",gao());
}
return 0;
}
inline int read() {
int x = 0, w = 0;
char ch = 0;
while (!isdigit(ch)) {
w |= (ch == '-');
ch = getchar();
}
while (isdigit(ch)) {
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
return w ? -x : x;
}