[POI2006]PAL-Palindromes

结论题:a,b是两个回文串,如果把他们连接在一起仍得到回文串,需要a,b的最小循环节相同。
求最小循环节,然后用map存储即可。
设字符串总长度为n,时间复杂度为O(n+log(n))。
#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
const int N=2e6+5,base=131;
int tot,prime[N],num[N];
bool mark[N];
int T,n,ans;
int bin[N],hash[N],b[N];
char str[N];
map<int,int>mp;

inline void get_prime()
{
	mark[1]=true;
	for (register int i=2; i<=2e6; ++i)
	{
		if (!mark[i]) prime[++tot]=i,num[i]=i;
		for (register int j=1; j<=tot; ++j)
		{
			if (prime[j]*i>2e6) break;
			mark[prime[j]*i]=true;
			num[prime[j]*i]=prime[j];
			if (i%prime[j]==0) break;
		}
	}
}

inline int get(int x,int y){return hash[y]-hash[x-1]*bin[y-x+1];}

signed main(){
	get_prime();	
	bin[0]=1;
	for (register int i=1; i<=2e6; ++i) bin[i]=bin[i-1]*base;
	scanf("%lld",&T);
	for (register int t=1; t<=T; ++t)
	{
		scanf("%lld",&n);
		scanf("%s",str+1);
		hash[0]=0;
		for (register int i=1; i<=n; ++i) hash[i]=hash[i-1]*base+(int)str[i];
		int len=n;
		int tot=0;
		while (len>1) b[++tot]=num[len],len/=num[len];
		len=n;
		for (register int i=1; i<=tot; ++i) if (get(1,n-len/b[i])==get(1+len/b[i],n)) len/=b[i];
		ans+=mp[hash[len]]; mp[hash[len]]++;
	}
	ans<<=1ll;
	ans+=T;
	printf("%lld\n",ans);
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值