牛客----Words Fascinating (SAM)

本文介绍了一种利用后缀自动机解决字符串子串问题的方法。通过倒序考虑每个字符串,并定义dp[i][j]表示考虑第i个串且新串以j开头的不同子串数量。同时,f[i][j]表示考虑第i个串且在后缀自动机的第j个节点上的不同子串数量。在后缀自动机上,由根节点到任意节点的路径对应一个字符串的子串,而到达终止节点的路径则对应一个字符串的后缀。利用逆拓扑序考虑,结合现有状态进行转移计算,最终得到所有本质不同的新串数量。
摘要由CSDN通过智能技术生成

题目链接

题面:
在这里插入图片描述

给定n个串,从每个串中选一个子串(可以为空),这些子串按顺序组成一个新串。
问本质不同的新串的个数。

我们倒着来考虑这些串。
我们设 dp [ i ] [ j ] 为倒序考虑到 第 i 个串 且 新串以 j 开头的本质不同的数量。
我们设 f [ i ] [ j ] 为考虑到 第 i 个串 且 倒序考虑到后缀自动机上第 j 个节点的本质不同的数量。
考虑转移:

if(nt[now][j]) f[now]=(f[now]+f[nt[now][j]])%mod;
else f[now]=(f[now]+dp[j])%mod;

如果当前考虑到了后缀自动机上第now个节点。
后缀自动机上从根节点出来到某一节点一定是某字符串的一个子串且这些子串本质不同。
后缀自动机上从根节点出来到某一终止节点一定是某字符串的一个后缀。
若某些后缀的前缀相同,那么他们的前缀共用一条路径。
即后缀自动机上,任意子串都是本质不同的。

我们逆拓扑序考虑。
假设当前节点nt [ now ] [ j ] 存在,即当前字符后面连接有字符 j ,为了不重复计算,我们令f [ now ] = ( f [ now ] + f [ nt [ now ] [ j ] ] ) % mod。因为在当前串上接上字符 j ,那么此后串上的字符 j 开头的子串都算进去了。
若 nt [ now ] [ j ] 不存在 ,即当前字符后面没有连接字符 j,那么f [ now ] = ( f [ now ] + dp [ j ] ) % mod。此时当前字符后面可以连接此后串上 j 开头的子串。

void _count(void)
    {
   

        for(int i=1;i<=cnt;i++) x[len[i]]++;
        for(int i=1;i<=cnt;i++) x[i]+=x[i-1];
        for(int i=1;i<=cnt;i++) y[x[len[i]]--]=i;
        for(int i=cnt;i>=1;i--)
        {
   
            int now=y[i];
            f[now]=1;
            for(int j=0;j<26;j++)
            {
   
                if(nt[now][j]) f[now]=(f[now]+f
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值