codeforces 494B Obsessive String

题目意思让我读了好久,可怜我渣渣英语。 题意大概是 先给你一个串 S  然后再给你一个串 T ,那么如果一个集合,这个集合里面有一些串  分别为 a1,a2,a3,a4...ax

如果 这些串都属于 S的子串并且 这些串不能含有相同的第某个字符,即是不能重复   且 T 也是这些串每个串的子串,那么这个集合就是一个合法集合,问有多少个合法集合

举个例子吧  ababa  和 aba   那么符合条件的集合 有5个  分别 是   { aba }  ,{abab} ,{ababa}. {baba},{aba}. 

首先  考虑 DP[I] 表示 以 i 为起点 必须包含 i 的到串尾的 合法集合的个数 

那么先用KMP记录出 以I 开头 长为 |T|  刚好匹配  记为 fg[i]=1;  i从 0到 n-1;

然后 当 fg[i] 为  0 时  就为 dp[i] =dp[i+1]

如果 当 fg[i] 为 1  那么  dp[i]=n-i-m+1  dp[i]+=dp[i+m]+d[i+m+1]*2+dp[i+m+2]*3...

后面这些东西 可以用 前缀和的前缀和 统计


代码如下

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef long long LL;
#define mod 1000000007
#define NN 200000
LL dp[NN+10];
char mo[NN+10],s[NN+10];
int next[NN+10],fg[NN+10];
LL sum1[NN+10],sum2[NN+10];
void get_next(int m)
{
    next[0]=next[1]=0;
    for(int i=1;i<m;i++)
    {
        int j=next[i];
        while(j && mo[i]!=mo[j]) j=next[j];
        next[i+1]= mo[i]==mo[j]?j+1:0;
    }
}
void Find(int n,int m)
{
    int j=0;
    for(int i=0;i<n;i++)
    {
        while(j && mo[j]!=s[i]) j=next[j];
        if(mo[j]==s[i]) j++;
        if(j==m)
        {
            j=next[j];
            fg[i-m+1]=1;
        }
    }
}
int main()
{
    while(scanf("%s",s)!=EOF)
    {
        scanf("%s",mo);
        int m=strlen(mo);
        int n=strlen(s);
        memset(fg,0,sizeof(fg));
        memset(sum1,0,sizeof(sum1));
        memset(sum2,0,sizeof(sum2));
        memset(dp,0,sizeof(dp));
        get_next(m);
        Find(n,m);
        for(int i=n-1;i>=0;i--)
        {
            if(fg[i]==1)
            {
                dp[i]+=n-i-m+1;
                dp[i]%=mod;
                if(i+m <= n)
                    dp[i]=(dp[i]+sum2[i+m])%mod;
                sum1[i]=(sum1[i+1]+dp[i])%mod;
                sum2[i]=(sum2[i+1]+sum1[i])%mod;
            }
            else
            {
                dp[i]=dp[i+1];
                sum1[i]=(sum1[i+1]+dp[i])%mod;
                sum2[i]=(sum2[i+1]+sum1[i])%mod;
            }

        }
        LL ans=0;
        for(int i=0;i<n;i++)
        {
            ans=(ans+dp[i])%mod;
        }
        printf("%lld\n",ans);
    }


    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值