CF17E Palisection(manacher/回文树)

CF17E Palisection(manacher/回文树)

Luogu

题解时间

直接正难则反改成求不相交的对数。

manacher求出半径之后就可以差分搞出以某个位置为开头/结尾的回文串个数。

然后就容易求出不相交的对数,用总数减去即为答案。

啊是的这题好像也可以用回文树做。

#include<bits/stdc++.h>
using namespace std;
namespace RKK
{
const int N=4000011,mo=51123987;
void doadd(int &a,int b){if((a+=b)>=mo) a-=mo;}
int add(int a,int b){return (a+=b)>=mo?a-mo:a;}

int n,m;char s[N];

int r[N],mar,mai;

int tot,ls[N],rs[N];

int main()
{
	scanf("%d%s",&n,s+1);
	s[0]='@';for(int i=n;i;i--)s[i<<1]=s[i],s[(i<<1)-1]='#';s[n<<1|1]='#';m=n<<1|1;
	for(int i=1;i<=m;i++)
	{
		r[i]=i<=mar?min(r[(mai<<1)-i],mar-i+1):1;
		while(s[i-r[i]]==s[i+r[i]]) r[i]++;
		if(i+r[i]>mar) mar=i+r[i]-1,mai=i;
		doadd(tot,r[i]>>1),ls[i-r[i]+1]++,ls[i+1]--,rs[i]++,rs[i+r[i]]--;
	}
	for(int i=1;i<=m;i++) doadd(ls[i],ls[i-1]),doadd(rs[i],rs[i-1]);
	tot=1ll*tot*(tot-1)/2%mo; 
	for(int i=1,s=0;i<=n;i++) doadd(tot,mo-1ll*s*ls[i<<1]%mo),doadd(s,rs[i<<1]);
	printf("%d
",tot);
	return 0;
}
}
int main(){return RKK::main();}
原文地址:https://www.cnblogs.com/rikurika/p/12846187.html