zoukankan      html  css  js  c++  java
  • [加强版] Codeforces 835D Palindromic characteristics (回文自动机、DP)

    题目链接: https://codeforces.com/contest/835/problem/D

    注: 欢迎移步 https://codeforces.com/blog/entry/67839

    题意: 一个回文串是(1)-回文的,如果一个回文串的左半部分和右半部分一样且都是(k)-回文串(右半部分是指长度为该串长度除以二下取整的后缀),则该串为((k+1))回文串,满足该串是(k)回文串的最大(k)称作该串的回文级别。给定一个串(s), 对于每一个(k=1,2,...,n)求出该串中有多少个位置不同的(k)-回文串。(nle 5 imes 10^6). (除数据范围外与原题均相同)

    题解: (n^2)的做法肯定是以子串为状态进行dp, 但是显然废状态太多了,只有回文串dp值非零,而一个串本质不同的回文串的个数是(O(n))的。

    所以,以本质不同的回文串作为状态进行dp. 本质不同的回文串一一对应回文自动机上的节点。设(f[x])表示(x)节点代表回文串的回文级别。

    然后转移方程显然: 若(x)不存在长度为([frac{x}{2}])(中括号表示下取整)的回文后缀,则(dp[x]=1), 否则(dp[x])等于那个回文后缀的(dp)值+1.

    dp完之后,我们求的是本质不同,但是题目要求求位置不同,所以还需要再统计一下每个点的子树大小。

    时间复杂度(O(n)).

    代码 (Codeforces 835D AC)

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #define llong long long
    using namespace std;
    
    const int N = 1e6+2;
    const int LGN = 23;
    const int S = 26;
    int son[N+3][S+1];
    int fail[N+3];
    int len[N+3];
    int sz[N+3];
    int tsz[N+3];
    char a[N+3];
    int dp[N+3];
    int bd[N+3];
    int ord[N+3];
    int buc[N+3];
    llong ans[N+3];
    int n,siz,lstpos;
    
    void initPAM()
    {
    	siz = lstpos = 1; fail[0] = fail[1] = 1; len[1] = -1; len[0] = 0; bd[0] = 0; bd[1] = 1;
    }
    
    void insertchar(int id)
    {
    	int p = lstpos;
    	while(a[id]!=a[id-len[p]-1]) {p = fail[p];}
    	if(!son[p][a[id]])
    	{
    		siz++; int u = siz,v = fail[p];
    		while(a[id]!=a[id-len[v]-1]) {v = fail[v];}
    		fail[u] = son[v][a[id]]; son[p][a[id]] = u; len[u] = len[p]+2;
    		if(len[u]<=2) {bd[u] = fail[u];}
    		else
    		{
    			bd[u] = bd[p];
    			while(a[id]!=a[id-len[bd[u]]-1] || (len[bd[u]]+2)*2>len[u])
    			{
    				bd[u] = fail[bd[u]];
    			}
    			bd[u] = son[bd[u]][a[id]];
    		}
    		if(len[bd[u]]==(len[u]>>1)) {dp[u] = max(0,dp[bd[u]])+1;}
    		else {dp[u] = 1;}
    	}
    	sz[son[p][a[id]]]++;
    	lstpos = son[p][a[id]];
    }
    
    int main()
    {
    	initPAM();
    	scanf("%s",a+1); n = strlen(a+1);
    	for(int i=1; i<=n; i++) a[i]-=96;
    	for(int i=1; i<=n; i++) {insertchar(i);}
    	for(int i=2; i<=siz; i++) {buc[len[i]]++;}
    	for(int i=1; i<=n; i++) {buc[i] += buc[i-1];}
    	for(int i=siz; i>=2; i--) {ord[(buc[len[i]]--)+1] = i;}
    	ord[0] = 1; ord[1] = 0;
    	for(int j=siz; j>=2; j--)
    	{
    		int u = ord[j];
    		sz[fail[u]] += sz[u];
    	}
    	for(int j=2; j<=siz; j++)
    	{
    		ans[dp[j]] += (llong)sz[j];
    	}
    	for(int j=LGN-1; j>=1; j--) ans[j] += ans[j+1];
    	for(int i=1; i<=n; i++) printf("%I64d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    近期遇到的问题 与 总结
    最近使用的控件整理
    sass import 小记
    Visual studio 相关插件
    nodeJs中linq.js学习
    C++ Socket编程步骤
    Qt 多线程同步 与 通信
    信号槽 与事件区别
    Qt 关键宏 转自网络整理
    mongoDB windows安装
  • 原文地址:https://www.cnblogs.com/suncongbo/p/11063316.html
Copyright © 2011-2022 走看看