题目描述:给n个可用字母,组成长为m的串s,其中有w个子串t是不能在这些串s中出现的,请问这样的串s有多少种?
思路:先建立一个ac自动机,并且标记每个w的结束节点end=1,同时把fail指向end=1的点的end也改写为1。现在要计算从root走m步(不能经过end=1的点)一共有多少种走法。采用DP的写法,记dp[step][i]表示从root走step步可以到j点。如果i能一步走到j,那么dp[step][j]=dp[step-1][i](所有满足的i都加进来)。
//POJ 1625 关键代码段
void build(){
queue <int> Q;
fail[root] = root;
for(int i = 0;i < n;i++)
if(nxt[root][i] == -1)
nxt[root][i] = root;
else{
fail[nxt[root][i]] = root;
Q.push(nxt[root][i]);
}
while(!Q.empty()){
int Now = Q.front(); Q.pop();
for(int i = 0;i < n;i++){
if(nxt[Now][i] == -1)
nxt[Now][i] = nxt[fail[Now]][i];
else{
fail[nxt[Now][i]] = nxt[fail[Now]][i];
end[nxt[Now][i]] |= end[nxt[fail[Now]][i]];//end的重标
Q.push(nxt[Now][i]);
}
}
}
}
void solve(int step)
{
memset(dp,0,sizeof(dp));
dp[0][0][0] = 1; //大数一定会爆,用数组模拟
for(int k = 1;k <= step;k++){ //注意了,一定是把步数放在最外面统计
for(int i = 0;i < L;i++){
if(end[i]) continue; //end是不能实现字段的结束标识,不可到达
for(int j = 0;j < n;j++){
int thi = nxt[i][j];
if(end[thi]) continue;
ADD(dp[k][thi],dp[k-1][i]);
}
}
}
for(int i = 1;i < L;i++){ //这里是把所有结点上的可能加起来,不要重复加结点0
if(end[i]) continue;
ADD(dp[step][0],dp[step][i]);
}
pin(dp[step][0]);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。