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


  • 相关阅读:
    echarts 柱状图
    echarts 双y轴渐变色进度条
    echarts 折线图
    算法系列一:本质以及特征
    导致薪水低的九大行为表现
    Tomcat使用shutdown.sh无法关闭
    定时将上月的数据导入到Oracle中,并更新指定的列
    定时抛转数据 crontab
    微服务主要模块
    tk.mybatis 调用oracle,生成ID
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793826.html
Copyright © 2011-2022 走看看