【BZOJ2160】拉拉队排练(回文树)

【BZOJ2160】拉拉队排练(回文树)

题面

BZOJ

题解

看着题目,
直接构建回文树
求出每个回文串的出现次数
直接按照长度\(sort\)一下就行了
然后快速幂算一下答案就出来了

这题貌似可以用Manacher做吧
求出以每个字符为中心的回文串的最大长度
然后搞一下前缀和就行了

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 1200000
#define MOD 19930726
int size[MAX];
char ch[MAX];
int n,ans=1;
ll K,sum;
pair<int,int> S[MAX];
int fpow(int a,int b)
{
	int s=1;
	while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}
	return s;
}
struct PT
{
	struct Node
	{
		int son[26];
		int ff,len;
	}t[MAX];
	int last,tot;
	void init()
	{
		t[tot=1].len=-1;
		t[1].ff=t[0].ff=1;
	}
	void extend(int c,int n,char *s)
	{
		int p=last;
		while(s[n-t[p].len-1]!=s[n])p=t[p].ff;
		if(!t[p].son[c])
		{
			int v=++tot,k=t[p].ff;
			while(s[n-t[k].len-1]!=s[n])k=t[k].ff;
			t[v].len=t[p].len+2;
			t[v].ff=t[k].son[c];
			t[p].son[c]=v;
		}
		size[last=t[p].son[c]]++;
	}
	void Calc()
	{
		for(int i=tot;i;--i)size[t[i].ff]+=size[i];
	}
}PT;
int main()
{
	scanf("%d %lld",&n,&K);
	scanf("%s",ch+1);
	PT.init();
	for(int i=1;i<=n;++i)PT.extend(ch[i]-97,i,ch);
	PT.Calc();
	for(int i=2;i<=PT.tot;++i)S[i-1]=make_pair(-PT.t[i].len,size[i]);
	sort(&S[1],&S[PT.tot]);
	for(int i=1;i<PT.tot;++i)
	{
		if(S[i].first%2==0)continue;
		ll pl=min(K,1ll*S[i].second);
		ans=1ll*ans*fpow(-S[i].first,pl)%MOD;
		K-=pl;
		if(!K)break;
	}
	if(!K)printf("%d\n",ans);
	else puts("-1");
	return 0;
}

posted @ 2018-02-23 20:05  小蒟蒻yyb  阅读(320)  评论(0编辑  收藏  举报