[ BZOJ 2160 ] 拉拉队排练
\(\\\)
\(Description\)
一个由小写字母构成的长为\(N\)的字符串,求前\(K\)长的奇数长度回文子串长度之积,对\(19930726\)取模后的答案。
- \(N\in [1,10^6]\),\(K\in [1,10^{12}]\)
\(\\\)
\(Solution\)
- \(Manacher\)处理出所有位置的回文半径,因为答案要求奇数长度,所以不用插入特殊字符,在原串上直接跑\(Manacher\)就好,回文半径内的以当前点为回文中心的每一个子串都是回文串。
- 所以开一个长度的桶,只给回文半径对应的最长子串长度打标记,显然一个标记代表着后面所有位置都\(+1\),所以计算的时候,一个长度的回文子串个数是长度标记的前缀和。
- 要求的\(K\)非常大,快速幂处理。
\(\\\)
\(Code\)
#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1000010
#define R register
#define gc getchar
#define mod 19930726
using namespace std;
typedef long long ll;
char c,s[N];
ll m,res=1,sum;
int n,len[N],cnt[N];
inline void init(){
scanf("%d%lld",&n,&m);
while(!isalpha(c=gc()));
s[1]=c; s[0]='['; s[n+1]=']';
for(R int i=2;i<=n;++i) s[i]=gc();
}
inline void manacher(){
for(R int i=1,p=0,mr=0;i<=n;++i){
len[i]=i>mr?1:min(mr-i+1,len[(p<<1)-i]);
while(s[i-len[i]]==s[i+len[i]]) ++len[i];
if(i+len[i]-1>mr){p=i;mr=i+len[i]-1;}
++cnt[(len[i]<<1)-1];
}
}
inline ll qpow(ll x,ll t){
ll res=1;
while(t){
if(t&1) (res*=x)%=mod;
(x*=x)%=mod; t>>=1;
}
return res;
}
int main(){
init();
manacher();
for(R int i=((n/2)<<1)+1;i>=1;i-=2){
sum+=(ll)cnt[i];
if(sum>=m){printf("%lld",(res*qpow(i,m))%mod);return 0;}
(res*=qpow(i,sum))%=mod; m-=sum;
}
puts("-1");
return 0;
}