链接:http://zerojudge.tw/ShowProblem?problemid=b179
做这道题首先要对ac自动机理解透彻!!
蛮好的一道题目,每一天字符串除了会在尾部扩展一个,开头的字符还会消失使得长度变短。最后要统计n天的时间内多少个串消失了,多少个串生病住院了(包含了病毒串)
要描述这个状态,需要考虑经过了几天 串的长度是多少 停留在哪个节点,一般自动机 dp都是这样,很好想,关键是怎么转移
首先在尾部扩展一个字符,这是一般自动机DP都有的转移
但是在头部删除一个字符就有点妙了
分三种情况
1:串的长度为1 时,删除后就消失了,这个时候加上当前状态
2:串的长度恰好为所停留在节点的深度,长度减一后无法停留在当前节点,那往哪里走呢?显然是fail指针!
3:串的长度大于这个节点的深度,那肯定还是长度减一,停留在当前节点。
长度小于当前节点的深度都是非法状态,不用考虑
还有个注意点就是第一维要用滚动数组,滚动时别忘记清空
错了一次,数组开小了。
一组数据,帮助调试
a
3
3
ab
cc
dd
4 14
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
const int M = 1510;
const int CD = 4;
int ID[128];;
int ch[M][CD];
int Q[M];
int fail[M];
int sz;
int val[M];
void Init(){
sz=1;
memset(ch[0],0,sizeof(ch[0]));
fail[0]=0; val[0]=0;
ID['a']=0; ID['b']=1;ID['c']=2;ID['d']=3;
}
int dep[M];
void Insert(char *s) {
int p=0; int d=0;
for(;*s;s++) {
d++;
int c=ID[*s];
if(!ch[p][c]) {
memset(ch[sz],0,sizeof(ch[sz]));
val[sz]=0;
dep[sz]=d;
ch[p][c]=sz++;
}
p=ch[p][c];
}
val[p]=1;
}
void Construct() {
int *s=Q,*e=Q;
for(int i=0;i<CD;i++) {
if(ch[0][i]) {
fail[ch[0][i]] = 0;
*e++ = ch[0][i];
}
}
while(s!=e) {
int u = *s++;
for(int i=0;i<CD;i++) {
int &v = ch[u][i];
if(v) {
*e++ = v;
fail[v] = ch[fail[u]][i];
val[v] |= val[fail[v]];
} else {
v = ch[fail[u]][i];
}
}
}
}
const int mod = 10007;
char str[110];
int dp[2][110][1510];
bool init(char *s)
{
memset(dp,0,sizeof(dp));
int p=0,len=0;
for(;*s;s++)
{
len++;
int c=ID[*s];
p=ch[p][c];
}
dp[0][len][p]=1;
if(val[p])return false;
return true;
}
void solve(int n)
{
bool flag=init(str);
if(!flag) {
puts("0 1\n");return ;
}
int x=0,ans=0,ret=0;
for(int i=0;i<n;i++)
{
x^=1;
for(int y=1;y<=100;y++) memset(dp[x][y],0,sizeof(dp[x][y]));
for(int j=0;j<sz;j++)if(!val[j])
{
for(int len=1;len<=100;len++) if(dp[x^1][len][j])//串长度为len 停留在j节点
{
if(len == 1) {
ans=(ans+dp[x^1][len][j])%mod;
} else if(len==dep[j]) {
dp[x][len-1][fail[j]] += dp[x^1][len][j];
dp[x][len-1][fail[j]] %= mod;
} else if(len>dep[j]){
dp[x][len-1][j] += dp[x^1][len][j];
dp[x][len-1][j] %= mod;
}
for(int k=0;k<4;k++) {
int to=ch[j][k];
dp[x][len+1][to] += dp[x^1][len][j];
dp[x][len+1][to] %= mod;
if(val[to]) {
ret=(ret+dp[x^1][len][j])%mod;
}
}
}
}
}
printf("%d %d\n",ans,ret);
}
int main(){
char s[110];
Init();
scanf("%s",str);
int n,p;
scanf("%d%d",&n,&p);
for(int i=0;i<p;i++)
{
scanf("%s",s);
Insert(s);
}
Construct();
solve(n);
return 0;
}
/*
a
3
3
ab
cc
dd
4 14
*/