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;
    }
    


  • 相关阅读:
    Java Jsoup Spider抓取数据入库
    DevOps详解
    七款做好DevOps的强大工具
    DevOps 初学者的入门指南
    DevOps必备的20款顶级工具
    Docker 三大核心工具
    Deploying Docker images via SSH
    Shell实现判断进程是否存在并重新启动脚本
    记录:50多行程序中找出多写的一个字母e
    Android 平板中 自己定义键盘(popuwindow) 居于屏幕左下方 仿微信的password输入界面
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793827.html
Copyright © 2011-2022 走看看