URAL 1158 AC自动机上的简单DP+大数

时间:2023-03-09 19:09:06
URAL 1158 AC自动机上的简单DP+大数

题目大意

在一种语言中的字母表中有N(N<=50)个字母,每个单词都由M(M<=50)个字母构成,因此,一共可以形成N^M个单词。但是有P(P<=10)个串是被禁止的,也就是说,任何单词的子串都不能包含这P个串中的任意一个。问按照上述规则,能产生的合法串一共有多少个? 例如:N=3 M=3 P=3 字母表中的三个字符是QWE 被禁止的串为”QQ”,”WEE”,”Q”,则合法的串一共有7个。

这题目相当于通过步数对AC自动机上每一个点的状态进行DP

dp[i][j]表示到达i这个点,走了j步存在多少种方法

总是从上一步推到下一步

写成滚动数组也不会有问题

这里要注意在AC自动机更新操作时,要将每个串末尾能到达的fail位置也记上标记,题解中有注释解释

 #include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define clr(x) memset(x , 0 , sizeof(x))
#define set(x) memset(x , -1 , sizeof(x))
typedef long long LL ;
#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define For( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define rev( i , a , b ) for ( int i = a ; i >= b ; -- i )
map<char , int> mp; const int CHAR_SIZE = ;
const int MAX_SIZE = ;
const int M = ;
int n,m,p; struct BigInt {
int wei , a[];
BigInt(){
wei = ;
memset(a , , sizeof(a));
}
void init(){
wei = ;
memset(a , , sizeof(a));
}
void print(){
for(int i=wei- ; i>= ; i--) printf("%d" , a[i]);
printf("\n");
}
BigInt operator+(BigInt m){
BigInt ret;
int ma = max(wei , m.wei);
for(int i= ; i<ma ; i++){
ret.a[i] += a[i]+m.a[i];
if(ret.a[i]>=) ret.a[i+]++,ret.a[i]-=;
}
if(ret.a[ma]) ret.wei = ma+;
else ret.wei = ma;
return ret;
}
}; struct AC_Machine{
int ch[MAX_SIZE][CHAR_SIZE] , val[MAX_SIZE] , fail[MAX_SIZE];
int sz; void init(){
sz = ;
clr(ch[]) , clr(val);
} void insert(char *s){
int n = strlen(s);
int u= ;
for(int i= ; i<n ; i++){
int c = mp[s[i]];
if(!ch[u][c]){
clr(ch[sz]);
val[sz] = ;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = ;
} void get_fail(){
queue<int> Q;
fail[] = ;
for(int c= ; c<n ; c++){
int u = ch[][c];
if(u){Q.push(u);fail[u]=;}
}
while(!Q.empty()){
int r = Q.front();
Q.pop();
//比如is, history都是非法的,history中有is,那么history访问到它的s时也是非法的
val[r] |= val[fail[r]];
for(int c= ; c<n ; c++){
int u = ch[r][c];
if(!u){ch[r][c] = ch[fail[r]][c]; continue;}
fail[u] = ch[fail[r]][c];
Q.push(u);
}
}
}
}ac; char str[];
BigInt dp[MAX_SIZE][]; BigInt solve(int n , int step)
{
for(int i= ; i<ac.sz ; i++)
for(int j= ; j<=step ; j++){
dp[i][j].init();
}
dp[][].wei = dp[][].a[] = ;
for(int i= ; i<=step ; i++){
for(int j= ; j<ac.sz ; j++){
for(int k= ; k<n ; k++)
if(!ac.val[ac.ch[j][k]]){
dp[ac.ch[j][k]][i] = dp[ac.ch[j][k]][i]+dp[j][i-];
}
}
}
BigInt ret = BigInt();
for(int j= ; j<ac.sz ; j++) ret = ret+dp[j][step];
return ret;
} int main()
{
// freopen("in.txt" , "r" , stdin);
// freopen("out.txt" , "w" , stdout);
while(~scanf("%d%d%d" , &n , &m , &p)){
mp.clear();
getchar();
gets(str);
for(int i= ; i<strlen(str) ; i++) mp[str[i]] = i;
ac.init();
for(int i= ; i<=p ; i++){
gets(str);
ac.insert(str);
}
ac.get_fail();
BigInt ret = solve(n , m);
ret.print();
}
return ;
}