BZOJ2160: 拉拉队排练(Manacher)
Description
艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了。拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛。所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多么的重要。拉拉队的选拔工作已经结束,在雨荨和校长的挑选下,n位集优秀的身材、舞技于一体的美女从众多报名的女生中脱颖而出。这些女生将随着篮球队的小伙子们一起,和对手抗衡,为艾利斯顿篮球队加油助威。一个阳光明媚的早晨,雨荨带领拉拉队的队员们开始了排练。n个女生从左到右排成一行,每个人手中都举了一个写有26个小写字母中的某一个的牌子,在比赛的时候挥舞,为小伙子们呐喊、加油。雨荨发现,如果连续的一段女生,有奇数个,并且他们手中的牌子所写的字母,从左到右和从右到左读起来一样,那么这一段女生就被称作和谐小群体。现在雨荨想找出所有和谐小群体,并且按照女生的个数降序排序之后,前K个和谐小群体的女生个数的乘积是多少。由于答案可能很大,雨荨只要你告诉她,答案除以19930726的余数是多少就行了。
Input
输入为标准输入。第一行为两个正整数n和K,代表的东西在题目描述中已经叙述。接下来一行为n个字符,代表从左到右女生拿的牌子上写的字母。
Output
输出为标准输出。输出一个整数,代表题目描述中所写的乘积除以19930726的余数,如果总的和谐小群体个数小于K,输出一个整数-1。
Sample Input
5 3
ababa
ababa
解题思路:
第一眼看到k<=1000,000,000,000懵逼了,回文串怎么会有这么多。
结果再看一眼题才知道这个回文串是可以居于其他回文串正中间的,那就和平了。
先Manacher求出以每个点为中间的最长回文串长度放入桶中。
很显然以 i最长奇数长的最长回文串长为 l 有 x 个,那么 l-2 也有 x 个。
快速幂一下就好了^_^
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using std::min; 5 typedef long long lnt; 6 const lnt mod=19930726; 7 char a[2000000]; 8 int l[3000000]; 9 int f[3000000]; 10 int s[2000000]; 11 int cnt; 12 int n; 13 lnt k; 14 lnt ans; 15 lnt Qpw(lnt x,lnt y) 16 { 17 lnt ans=1; 18 while(y) 19 { 20 if(y&1) 21 ans=ans*x%mod; 22 x=x*x%mod; 23 y/=2; 24 } 25 return ans; 26 } 27 int main() 28 { 29 scanf("%d%lld",&n,&k); 30 scanf("%s",a+1); 31 l[cnt]='@'; 32 for(int i=1;i<=n;i++) 33 { 34 l[++cnt]='@'; 35 l[++cnt]=a[i]; 36 } 37 l[++cnt]='@'; 38 int mx=1; 39 f[1]=1; 40 for(int i=2;i<=cnt;i++) 41 { 42 f[i]=min(f[mx*2-i],f[mx]+mx-i); 43 while(f[i]+i<=cnt&&l[f[i]+i]==l[i-f[i]]) 44 f[i]++; 45 if(mx+f[mx]<f[i]+i) 46 mx=i; 47 if((f[i]-1)&1) 48 s[f[i]-1]++; 49 } 50 ans=1; 51 lnt sum=0; 52 for(int i=n;i>=1;i--) 53 { 54 if(i%2==0) 55 continue; 56 sum+=s[i]; 57 if(k>sum) 58 { 59 ans=ans*Qpw(i,sum)%mod; 60 k-=sum; 61 }else{ 62 ans=ans*Qpw(i,k)%mod; 63 k-=sum; 64 break; 65 } 66 } 67 if(k>0) 68 ans=-1; 69 printf("%lld\n",ans); 70 return 0; 71 }