您的位置:首页 > Web前端 > JavaScript

BZOJ1030 JSOI2007 文本生成器 题解&代码

2016-03-11 16:30 519 查看
题意:给出n个匹配串,询问:对于长度为m的串,有多少个串至少包含一个匹配串(答案对10007取模)

题解:

“至少包含一个匹配串的长度为m的串”,那么很容易转化为“所有串除去不包含任何匹配串的长度为m的串”

然后就是喜闻乐见的AC自动机上的dp了,dp方程显然是dp[i][j]表示长度为i的串匹配到j位时有多少不包含任何匹配串

有:dp[i][ch[j][k]]+=dp[i-1][j]

即孩子节点一定由有效父亲节点推知(节点本身flag指针就是true的当然是0)

/**************************************************************
Problem: 1030
User: Rainbow6174
Language: C++
Result: Accepted
Time:76 ms
Memory:4396 kb
****************************************************************/

#include <iostream>
#include <cstdio>
#include <cstring>
#define MOD 10007
using namespace std;
const int maxt = 6005;
int n, m, tot, ans = 1, temp, ch[maxt][26], fail[maxt], q[maxt], dp[105][maxt];
char s[105];
bool flag[maxt];
void newnode(int x, int v)
{
ch[x][v]=++tot;
}
void addtrie(char s[])
{
int x = 0, p = 0, len = strlen(s);
while( p < len )
{
temp = s[p]-'A';
if ( !ch[x][temp] ) newnode(x, temp);
x = ch[x][temp];
p++;
}
flag[x] = 1;
}
void AC(void)
{
int h = 0, t = 0;
for(int i = 0; i < 26; i++)
if(ch[0][i]) q[t++] = ch[0][i];
while( h < t )
{
temp = q[h++];
for(int i = 0; i < 26; i++)
if( !ch[temp][i] ) ch[temp][i] = ch[fail[temp]][i];
else fail[ch[temp][i]] = ch[fail[temp]][i],
flag[ch[temp][i]] |= flag[fail[ch[temp][i]]],
q[t++] = ch[temp][i];
}
}
int main(void)
{
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++)
{
scanf("%s", s);
addtrie(s);
}
AC();
dp[0][0] = 1;
for(int i = 1; i <= m; i++)
{
for(int j = 0; j <= tot; j++)
{
if(flag[j] || !dp[i-1][j]) continue;
for(int k = 0; k < 26; k++)
{
dp[i][ch[j][k]] += dp[i-1][j];
dp[i][ch[j][k]] %= MOD;
}
}
ans*=26;
ans%=MOD;
}
//cout<<ans<<endl;
for(int i = 0; i <= tot; i++)
{
//cout<<i<<' '<<flag[i]<<endl;
if(!flag[i])
{
//cout<<dp[m][i]<<endl;
ans -= dp[m][i];
ans += MOD;
ans %= MOD;
}
}
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: