zoukankan      html  css  js  c++  java
  • 洛谷2375 NOI2014动物园(KMP)

    题目链接:
    题目.

    简单一点来说,这个题就是求一个字符串的(num)数组的和,其中有(num[i])表示1~i中有多少个不交叉的相等的前缀和后缀 的数目,要求一个(O(n))的做法

    QwQ
    感觉一看到这个题,其实没什么思路呀

    (KMP)的角度出发,对于一个(i)来说,显然(pre[i],pre[pre[i]])都是他的后缀,所以,我们貌似可以维护一个(num1)表示,可以交叉的 相等的 前缀和后缀的数目

    比较容易推出(num1[i]=num1[pre[i]]+1)

    这里可以理解成 在原来最多的数目上,再加上当前位匹配的贡献

    因为你对于当前的i的一些前后缀的比较和计算,已经在(pre[i])的时候计算过了

    那么我们怎么计算这个题目要求的(num)
    QwQ实际上对于每个(i)要找到一个小于(frac{i}{2})的最小递归层数的(pre) (递归的意思是(pre[pre[pre[i]]]))

    如果我们对于每一个(i)都暴力去做的话,时间复杂度肯定是不允许的,这时候我们就需要考虑一个性质:

    我们在循环到(i)时当前的(j)是不是可以重前一次的最长的不重叠的(j)得到呢?答案是肯定的,要么小于等于上一次的(j),要么等于上一次的(j+1)
    具体证明可以通过反证法来证明

    QwQ然后就直接像(KMP)那种跳的方式,跳(j)就可以的

    感觉这个题很有意思QwQ而且我还不是很懂呀

    留个坑吧

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    
    using namespace std;
    
    inline int read()
    {
       int x=0,f=1;char ch=getchar();
       while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
       while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
       return x*f;
    }
    
    const long long mod = 1e9+7;
    const int maxn = 1e6+1e2;
     
    int pre[maxn],num[maxn];
    char s[maxn];
    char s1[maxn];
    long long ans=0;
    int n;
    int t;
    
    void init()
    {
        for (int i=1;i<=maxn-10;i++) s[i]=s1[i];
        memset(pre,0,sizeof(pre));
        ans=1;
        memset(num,0,sizeof(num));                                             
    }
    
    int main()
    {
      cin>>t;
      while (t--)
      {
      	  init();
      	  scanf("%s",s+1);
      	  n=strlen(s+1);
          pre[1]=0;
          num[1]=1;	 
      	  for (int i=2;i<=n;i++)
      	  {
      	  	  int j=pre[i-1];
              while (j && s[j+1] !=s[i]) j=pre[j];
              if (s[j+1]==s[i]) j++;
              pre[i]=j;
              num[i]=num[j]+1;
      	  }
      	  int j=0;
      	  for (int i=1;i<=n;i++)
      	  {
      	  	 while (j && s[j+1] !=s[i]) j=pre[j];
      	  	 if (s[j+1]==s[i]) j++;
      	  	 while ((j << 1)>=i+1) j=pre[j];
      	  	 ans=ans*(num[j]+1)%mod;
      	  }
      	  cout<<ans<<endl;
      }                                                                     
      return 0;
    }
    
    
  • 相关阅读:
    instance of type of object.prototype.tostring 区别
    字符串属性及方法大总结
    数组属性及方法大总结
    在Vue中遇到的各种坑 及性能提升
    find、filter、map的区别
    react 的CDN 连接
    react开启一个项目 webpack版本出错
    react中的jsx详细理解
    Vue 在beaforeCreate时获取data中的数据
    vue点击时动态改变样式 ------- 最简单的方法
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10161374.html
Copyright © 2011-2022 走看看