zoukankan      html  css  js  c++  java
  • 【NOI2014T4】动物园-变形KMP

    测试地址:动物园

    做法:这题目很迷,一开始以为想出一种不用预处理的求num的方法,事实证明是错的......

    为了方便,设prefix(s,i)为字符串s的前i个字符组成的前缀,suffix(s,i)为字符串s的后i个字符组成的后缀。

    实际上我们要先求一个“假”的num数组,我们把它称为cnt数组,cnt[i]表示prefix(s,i)中既是其前缀又是其后缀的字符串个数(包括自身),于是我们就先预处理出next数组和cnt数组,然后再做一遍类似KMP的过程,这时候再注意重叠的问题:设pre为当前最大的满足prefix(prefix(s,i),pre)=suffix(prefix(s,i),pre)且pre≠i的数,如果pre*2>i,表示有重叠,则按照KMP的方法修正pre直到满足条件为止。于是我们可以知道,prefix(prefix(s,i),pre)=suffix(prefix(s,i),pre)且不重叠,且此时pre是满足条件的最大数,这时就可以得出num[i]=cnt[pre],累加答案即可。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define p 1000000007
    using namespace std;
    char s[1000010];
    int n,len;
    long long cnt[1000010],next[1000010],ans;
    
    void kmp()
    {
      int pre=0;
      next[1]=cnt[0]=0;ans=1;
      cnt[1]=1;
      for(int i=2;i<=len;i++)
      {
    	while(pre&&s[pre+1]!=s[i]) pre=next[pre];
    	if (s[pre+1]==s[i]) pre++;
    	next[i]=pre;
    	cnt[i]=cnt[pre]+1;
      }
      pre=0;ans=1;
      for(int i=2;i<=len;i++)
      {
        while(pre&&s[pre+1]!=s[i]) pre=next[pre];
    	if (s[pre+1]==s[i]) pre++;
    	while((pre<<1)>i) pre=next[pre];
    	ans*=cnt[pre]+1;
    	ans%=p;
      }
      printf("%lld
    ",ans);
    }
    
    int main()
    {
      scanf("%d",&n);
      s[0]='_';
      while(n--)
      {
        scanf("%s",s+1);
    	len=strlen(s)-1;
    	kmp();
      }
      
      return 0;
    }
    


  • 相关阅读:
    Python·安装扩展包的几种方法
    Arduino系列硬件资源介绍
    树莓派USB摄像头的使用
    树莓派frp服务器和客户端配置教程
    树莓派frp内网穿透
    用Windows远程桌面连接树莓派的方法
    控制窗体的位置和大小
    树霉派更换软件镜像源
    I2C的库函数应用示例
    I2C总线的Arduino库函数
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793827.html
Copyright © 2011-2022 走看看