zoukankan      html  css  js  c++  java
  • [NOI2014] 动物园

    Description

    (num[i]) 表示字符串 (S) 的前 (i) 个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,这种字符串的数量。给定一个字符串,求出它的 (num[])

    Solution

    (ans[i]) 表示字符串 (S) 的前 (i) 个字符构成的子串,既是它的后缀同时又是它的前缀,这种字符串的数量,显然 (ans[]) 可以在标准 KMP 的过程中很容易地处理出

    那么要得到每一个 (num[i]) 我们只需要以 (i) 为起点,用 (next()) 不断迭代,直到 (i'le frac i 2),此时的 (ans[i']) 就是所求

    每次都暴力迭代,复杂度显然无法接受,一种方案是对 (next())(2^j) 次迭代结果倍增处理,较为麻烦

    考虑在一个类似 KMP 的过程中动态维护 (j),但不同的是,每次处理完后,将 (j)(next()) 不断迭代,直到 (jle frac i 2),此时的 (ans[j]) 就是所求

    #include <bits/stdc++.h>
    using namespace std;
    
    const int mod = 1e9+7;
    
    char p[1000005];
    int n,m,fail[1000005],ans[1000005],num[1000005];
    
    void solve() {
        memset(p,0,sizeof p);
        memset(fail,0,sizeof fail);
        memset(ans,0,sizeof ans);
        memset(num,0,sizeof num);
    	cin>>p+1;m=strlen(p+1);
    	for(int i=2;i<=m;i++) {
    		int j=fail[i-1];
    		while(p[j+1]-p[i] && j) j=fail[j];
    		if(p[j+1]==p[i]) ++j;
    		fail[i]=j;
    		if(j>0) ans[i]=ans[j]+1;
    	}
    	for(int i=1;i<=m;i++) ans[i]++;
    	int j=0;
        for(int i=2;i<=m;i++) {
            while(p[j+1]-p[i] && j) j=fail[j];
            if(p[j+1]==p[i]) ++j;
            while(j*2>i && j) j=fail[j];
            num[i]=ans[j];
        }
        long long res=1;
        for(int i=2;i<=m;i++) res*=num[i]+1, res%=mod;
        cout<<res<<endl;
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        int n;
        cin>>n;
        while(n--) solve();
    }
    
    
  • 相关阅读:
    外部晶振的使用原因与内部RC振荡器的使用方法
    Linux系统下ifconfig命令使用及结果分析
    浅谈程序的内存布局
    物理内存与虚拟内存之间的映射
    如何正确理解套接字
    研究自动驾驶技术的算法需要哪些知识?
    如何防止头文件被重复包含或引用?
    虚拟机-VMware小结-汇总
    局域网内快速传输数据
    thingsboard安装
  • 原文地址:https://www.cnblogs.com/mollnn/p/13192220.html
Copyright © 2011-2022 走看看