• 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
    ",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
    ",ans);
    	}
    		
    }
    
  • 相关阅读:
    理解 Redis(3)
    理解 Redis(2)
    理解 Redis(1)
    git 的基本命令
    使用python实现计算器功能
    python函数说明内容格式错误
    python的小基础
    python去除读取文件中多余的空行
    数论-下属不可以和上司顶嘴!(可能是总结)
    其他-一大堆记录 (20 Dec
  • 原文地址:https://www.cnblogs.com/Lance1ot/p/9248692.html
Copyright © 2020-2023  润新知