P2375 动物园

入口

题目的大意就是输出以任意一个字符结尾,既是前缀,又是后缀,且长度不超过总长度的一半的方案书的乘积。

考虑使用kmp

在处理失配数组的同时,处理出来以每个字符结尾的时的,能有多少个前缀和后缀相同的数量。

然后在进行一次类似kmp的匹配,在这次匹配中处理出来答案。

先是为什么要处理多少个前缀和后缀相同的数量。

比如说,b是a的前缀和后缀,c是b的前缀和后缀(都合法)

然后c也肯定是a的前缀和后缀。处理出这个数组来,我们在寻求答案是只需要找到第一个符合条件的前缀&&后缀。加上我们预处理的个数就可以了。

//50分
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
char data[1010000];
int fail[1010000];
int num[1010000];
int main()
{   int m;
    scanf("%d",&m);
    while(m--)
    {
        scanf("%s",data);
        memset(fail,0,sizeof(fail));
        memset(num,0,sizeof(num));
        int len=strlen(data)-1;
        int k=0;num[1]=1;
        for(int i=1;i<=len;i++)
        {
            while(k&&data[i]!=data[k])
                k=fail[k];
            if(data[i]==data[k])    fail[i+1]=++k;
            num[i+1]=num[k]+1;  
        }
        long long ans=1;
        const long long mode=1e9+7;
        for(int i=1;i<=len+1;i++)
        {
            k=i;
            while((k<<1)>i)
                k=fail[k];
            ans=(ans*(num[k]+1))%mode;
        }
        printf("%lld\n",ans);
    }
}

这是每次暴力从尾利用失配数组暴力蹦跶。

然后我们考虑加速一波。

每次从当前尾部暴力蹦跶肯定不行,我们考虑一下加速。

我们再一次利用类似kmp的方法。

因为我们每次只向后推一位结尾。

我们就可以利用上一次失配指针的位置,进行转移。

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
char data[1000010];
int fail[1000010];
int num[1000010];
const long long mode=1e9+7;
int main()
{
    int m;scanf("%d",&m);
    while(m--)
    {
        memset(fail,0,sizeof(fail));
        memset(num,0,sizeof(num));
        scanf("%s",data);
        int len=strlen(data)-1;
        int k=0;num[1]=1;
        for(int i=1;i<=len;i++)
        {
            while(k&&data[i]!=data[k])  k=fail[k];
            if(data[i]==data[k])    fail[i+1]=++k;
            num[i+1]=num[k]+1;
        }
        k=0;
        long long ans=1;
        for(int i=1;i<=len+1;i++)
        {
            while(k&&data[i]!=data[k])  k=fail[k];
            while((k<<1)>=i)
                k=fail[k];
            if(data[i]==data[k])    ++k;
            ans=(ans*(num[k]+1))%mode;
        }
        printf("%lld\n",ans);
    }
        
}

猜你喜欢

转载自www.cnblogs.com/Lance1ot/p/9248692.html