有点毒瘤的一道题…
这题也是求不含若干个串的长度为m的字符串的个数,但数据会超longlong,因此之前的矩阵快速幂的方法做不了,只能用dp做。
ac自动机与dp结合的非常频繁,就当开个头吧。
#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <cstring>
#define fi first
#define se second
#define FIN freopen("in.txt","r",stdin)
#define FIO freopen("out.txt","w",stdout)
#define INF 0x3f3f3f3f
#define per(i,a,n) for(int i = a;i < n;i++)
#define rep(i,a,n) for(int i = n;i > a;i--)
#define pern(i,a,n) for(int i = a;i <= n;i++)
#define repn(i,a,n) for(int i = n;i >= a;i--)
#define fastio std::ios::sync_with_stdio(false)
#define all(a) a.begin(), a.end()
#define ll unsigned long long
#define pb push_back
#define endl "\n"
#define pii pair<int,int>
#define sc(n) scanf("%d", &n)
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
template<typename T> inline void _max(T &a,const T b){if(a<b) a = b;}
template<typename T> inline void _min(T &a,const T b){if(a>b) a = b;}
using namespace std;
//inline ll read(){
// ll a=0;int f=0;char p=getchar();
// while(!isdigit(p)){f|=p=='-';p=getchar();}
// while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();}
// return f?-a:a;
//}
const int maxn = 1000;
struct BigInteger{
int A[25];
enum{MOD = 10000};
BigInteger(){memset(A, 0, sizeof(A)); A[0]=1;}
void set(int x){memset(A, 0, sizeof(A)); A[0]=1; A[1]=x;}
void print(){
printf("%d", A[A[0]]);
for (int i=A[0]-1; i>0; i--){
if (A[i]==0){printf("0000"); continue;}
for (int k=10; k*A[i]<MOD; k*=10) printf("0");
printf("%d", A[i]);
}
printf("\n");
}
int& operator [] (int p) {return A[p];}
const int& operator [] (int p) const {return A[p];}
BigInteger operator + (const BigInteger& B){
BigInteger C;
C[0]=max(A[0], B[0]);
for (int i=1; i<=C[0]; i++)
C[i]+=A[i]+B[i], C[i+1]+=C[i]/MOD, C[i]%=MOD;
if (C[C[0]+1] > 0) C[0]++;
return C;
}
BigInteger operator * (const BigInteger& B){
BigInteger C;
C[0]=A[0]+B[0];
for (int i=1; i<=A[0]; i++)
for (int j=1; j<=B[0]; j++){
C[i+j-1]+=A[i]*B[j], C[i+j]+=C[i+j-1]/MOD, C[i+j-1]%=MOD;
}
if (C[C[0]] == 0) C[0]--;
return C;
}
};
BigInteger dp[55][110];
const int maxnode = 51;
int ch[maxn][maxnode]; //字典树
int cnt[maxn]; //单词出现次数
int sz;
int fail[maxn];
map<char,int> mp;
int idx = 0;
void init()
{
//mp['A'] = 0,mp['C']=1,mp['T']=2,mp['G']=3;
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
memset(cnt,0,sizeof(cnt));
//val[0] = 0;
cnt[0] = 0;
}
int id(char c)
{
if(!mp.count(c))mp[c] = idx++;
else return mp[c];
}
void insert(char str[], int len) //插入字符串
{
int u = 0;
per(i, 0, len)
{
int v = id(str[i]);
if (!ch[u][v])
{
memset(ch[sz], 0, sizeof(ch[sz]));
//val[sz] = 0;
cnt[sz] = 0;
ch[u][v] = sz++;
}
u = ch[u][v];
}
cnt[u]=1;
//在这里我们可以建立一个int-string的映射,以通过节点序号得知这个点是哪个单词的结尾
}
void getfail()
{
//所有模式串已插入完成
queue<int> q;
per(i, 0,maxnode)
{
if (ch[0][i])
{
fail[ch[0][i]] = 0;
q.push(ch[0][i]);
}
}
while (!q.empty())
{
int now = q.front();
q.pop();
per(i, 0, maxnode)
{
if (ch[now][i])
{
fail[ch[now][i]] = ch[fail[now]][i];
q.push(ch[now][i]);
}
else
ch[now][i] = ch[fail[now]][i];
}
cnt[now] |= cnt[fail[now]];
}
}
char s[100];
int main()
{
// #ifndef ONLINE_JUDGE
// int startTime = clock();
// FIN;
// #endif
//fastio;
//忘记初始化是小狗
//freopen("out.txt","w",stdout);
//ios::sync_with_stdio(false);
int n,m,p;
//cout << id('0');
while(~scanf("%d%d%d",&n,&m,&p)){
init();
scanf("%s",s);
per(i,0,n)id(s[i]);
per(i,0,p)
{
scanf("%s",s);
insert(s,strlen(s));
}
getfail();
dp[0][0].set(1);
pern(i,1,m)
{
per(j,0,sz)
{
per(k,0,n)
{
int v = ch[j][k];
if(!cnt[v]) dp[i][v] = dp[i][v]+dp[i-1][j];
}
}
}
BigInteger res;
//res.print();
per(i,0,sz)res = res+dp[m][i];
res.print();
}
// #ifndef ONLINE_JUDGE
// printf("\nTime = %dms\n", clock() - startTime);
// #endif
return 0;
}