[BZOJ1030]文本生成器 做题笔记

6 篇文章 0 订阅
3 篇文章 0 订阅

题目来源:http://www.lydsy.com/JudgeOnline/problem.php?id=1030
f[i][j],i表示走到第几步,j表示走到树上的哪个结点,j不能是单词结点或沿fail指针能找到单词的点。
对每一个f[i-1][j],处理每一个它所能到达的状态f[i][x],x表示j继续匹配a-z所能到达的结点。
最后统计f[m][j]之和,用总方案数减去之,即为答案。
有一个问题,如果文章里存在模式串里没有的字母怎么办?

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int mod=10007,N=6100;
int f[101][N];
int A[N][26],sum[N],fail[N],cnt;
bool danger[N];
queue<int> q;
char s[N];
int n,m,ans1,ans2=1;
void ins (char *s) {
    int n=strlen(s),p=1,c;
    for (int i=0;i<n;i++) {
        c=s[i]-'A';
        if (!A[p][c]) A[p][c]=++cnt;
        p=A[p][c];
    }
    danger[p]=1;
}
void getfail () {
    int p; fail[1]=0;
    q.push(1);
    while (!q.empty()) {
        p=q.front(); q.pop();
        for (int i=0;i<26;i++) {
            if (!A[p][i]) continue;
            int k=fail[p];
            while (!A[k][i]) k=fail[k];
            fail[A[p][i]]=A[k][i];
            if (danger[A[k][i]]) danger[A[p][i]]=1;
            q.push(A[p][i]);
        }
    }
}

void dp (int x) {
    for (int i=1;i<=cnt;i++) {
        if (danger[i]||!f[x-1][i]) continue;
        for (int j=0;j<26;j++) {
            int k=i;
            while (!A[k][j]) k=fail[k];
            f[x][A[k][j]]=(f[x][A[k][j]]+f[x-1][i])%mod;
        } 
    }
}

int main () {
    scanf("%d%d",&n,&m);
    cnt=1;
    for (int i=0;i<26;i++) A[0][i]=1;
    for (int i=1;i<=n;i++) {
        scanf("%s",s);
        ins(s);
    }
    getfail();
    f[0][1]=1;
    for (int i=1;i<=m;i++) dp(i);
    for (int i=1;i<=m;i++) 
        ans2=(ans2*26)%mod;
    for (int i=1;i<=cnt;i++) 
        if (!danger[i]) ans1=(ans1+f[m][i])%mod;
    printf("%d",(ans2-ans1+mod)%mod);
}
//实际上如果文章里有模式串中不存在的字母,那这一部分字母会被统计至编号为1的结点,最后统计时也会算上
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值