\(\\\)
\(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;
}