zoukankan      html  css  js  c++  java
  • $luogu2375[NOI2014]$

    (problem)

    其中,(next[i],next[next[i]],next[next[next[i]]]......)都是这个前缀串i的公共前后缀,而且只有它们是公共前后缀

    那么,我们其实只要在求(next)的过程中,顺便把这个公共前后缀的数量递推一下,就得到了一个弱化版的(num数组):可以重叠的公共前后缀数量,我们称之为(ans) 如何去除有重叠的?
    还是看上面那张图

    首先next数组有一个性质:(next[i] < inext[i]<i)
    也就是说,一旦有一个递归了(n)层的(next),比原前缀i的长度的一半要小,那么这个(next)的递推出的答案(ans)就是(i)(num)

    一个问题
    假如我们拿到的串是(1e6个'a'),那么上面那个算法就会被卡成O((n^2))道理的话大家可以想一想(每一次递归都只会把(next[i])变小1)

    那么我们需要做一个优化,来解决这个问题,而解决问题的核心就是:(减少重复递归)

    减少重复递归......(有没有想到什么?)

    没错,就是如同求(next)时一样的方法!

    我们将递归用的变量(j)的值不更新,这样,求完了i的答案以后,(j)的位置一定在(i/2)的左边,也就是它已经满足要求了

    这时再递归求解,总时间效率是(O(n))

    #include <bits/stdc++.h>
    using namespace std;
    const ll MOD=1e9+7;
    int n,fail[1000010],ans[1000010];
    ll cnt;
    char a[1000010];
    int main() {
    	int T,i,j;
    	scanf("%d",&T);
    	while(T--) {
    		scanf("%s",a);
    		n=strlen(a);
    		memset(fail,0,sizeof(fail));
    		j=0;
    		ans[0]=0;
    		ans[1]=1;
    		for(i=1; i<n; i++) {
    			while(j&&(a[i]!=a[j])) j=fail[j];
    			j+=(a[i]==a[j]);
    			fail[i+1]=j;
    			ans[i+1]=ans[j]+1;
    		}
    		j=0;
    		cnt=1;
    		for(i=1; i<n; i++) {
    			while(j&&(a[i]!=a[j])) j=fail[j];
    			j+=(a[i]==a[j]);
    			while((j<<1)>(i+1)) j=fail[j];
    			cnt=(cnt*(ll)(ans[j]+1))%MOD;
    		}
    		printf("%lld
    ",cnt);
    	}
    	return 0 ;
    }
    
    不存在十全十美的文章 如同不存在彻头彻尾的绝望
  • 相关阅读:
    c++实现执行脚本命令
    常用命令
    ssh2.cpp
    通过scp传输文件到多个主机
    启动和监控脚本
    centos 7.2 svn 安装
    SVN提交时必须填写备注信息 配置
    centos 7.2 配置mysql
    centos 7.2 配置Nginx
    js调试的时候用console.log("变量"+scrollTop+windowHeight)
  • 原文地址:https://www.cnblogs.com/qf-breeze/p/10551471.html
Copyright © 2011-2022 走看看