2160: 拉拉队排练
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2216 Solved: 858
[ Submit][ Status][ Discuss]
Description
艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了。拉拉队是篮球比赛的一个看点,好的拉拉队往往能帮助球队增加士气,赢得最终的比赛。所以作为拉拉队队长的楚雨荨同学知道,帮助篮球队训练好拉拉队有多么的重要。拉拉队的选拔工作已经结束,在雨荨和校长的挑选下,n位集优秀的身材、舞技于一体的美女从众多报名的女生中脱颖而出。这些女生将随着篮球队的小伙子们一起,和对手抗衡,为艾利斯顿篮球队加油助威。一个阳光明媚的早晨,雨荨带领拉拉队的队员们开始了排练。n个女生从左到右排成一行,每个人手中都举了一个写有26个小写字母中的某一个的牌子,在比赛的时候挥舞,为小伙子们呐喊、加油。雨荨发现,如果连续的一段女生,有奇数个,并且他们手中的牌子所写的字母,从左到右和从右到左读起来一样,那么这一段女生就被称作和谐小群体。现在雨荨想找出所有和谐小群体,并且按照女生的个数降序排序之后,前K个和谐小群体的女生个数的乘积是多少。由于答案可能很大,雨荨只要你告诉她,答案除以19930726的余数是多少就行了。
Input
输入为标准输入。第一行为两个正整数n和K,代表的东西在题目描述中已经叙述。接下来一行为n个字符,代表从左到右女生拿的牌子上写的字母。
Output
输出为标准输出。输出一个整数,代表题目描述中所写的乘积除以19930726的余数,如果总的和谐小群体个数小于K,输出一个整数-1。
Sample Input
5 3
ababa
ababa
Sample Output
45
【样例说明】
和谐小群体女生所拿牌子上写的字母从左到右按照女生个数降序排序后为ababa, aba, aba, bab, a, a, a, b, b,前三个长度的乘积为。
【样例说明】
和谐小群体女生所拿牌子上写的字母从左到右按照女生个数降序排序后为ababa, aba, aba, bab, a, a, a, b, b,前三个长度的乘积为。
HINT
总共20个测试点,数据范围满足:
Source
解题思路:这道题就是为回文树而生的。回文树可以统计某一回文子串在原串中出现的次数,所以直接枚举所有回文串,统计然后用快速幂即可。注意题目有个坑点,就是子回文串必须是奇数长度……
扫描二维码关注公众号,回复:
185788 查看本文章
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN = 1000005; const int INF = 0x3f3f3f3f; const int MOD=19930726; ll mpow(ll a,ll b){ ll ans=1; ll base=a; while(b>0){ if(b%2) ans=ans*base%MOD; base=base*base%MOD; b/=2; } return ans; } int len[MAXN];//表示编号为i的节点表示的回文串的长度(一个节点表示一个回文串) int nxt[MAXN][27];//表示编号为i的节点表示的回文串在两边添加字符c以后变成的回文串的编号 int fail[MAXN];//表示节点i失配以后跳转不等于自身的节点i表示的回文串的最长后缀回文串 int num[MAXN];//表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数。 int cnt[MAXN];//表示节点i表示的串的个数 int last; int S[MAXN]; int tot;//节点总数,即不同的回文串个数,记得-2 int N; int new_node(int l){ cnt[tot]=0; num[tot]=0; len[tot]=l; return tot++; } void init_tree(){ //memset(nxt,0,sizeof(nxt)); tot=0; new_node(0); new_node(-1); last=0; N=0; S[N]=-1; fail[0]=1; } int get_fail(int x){ while(S[N-len[x]-1]!=S[N]) x=fail[x]; return x; } void add_char(int c){ c-='a'; S[++N]=c; int cur=get_fail(last); if(!nxt[cur][c]){ int now=new_node(len[cur]+2); fail[now]=nxt[get_fail(fail[cur])][c]; nxt[cur][c]=now; num[now]=num[fail[now]]+1; } last=nxt[cur][c]; cnt[last]++; //return len[last]; } void count(){ for(int i=tot-1;i>=0;i--) cnt[fail[i]]+=cnt[i]; // int ans=0; // for(int i=2;i<tot;i++){ // ans+=cnt[i]; // } // cout<<ans<<endl; } char str[MAXN]; ll mp[MAXN]; int main(){ int N; ll K; scanf("%d%lld",&N,&K); scanf("%s",str); init_tree(); for(int i=0;i<N;i++) add_char(str[i]); count(); for(int i=2;i<tot;i++){ mp[len[i]]+=cnt[i]; } ll ans=1; for(int i=N;i>=1;i--){ if(mp[i]>0&&i%2){ if(K>mp[i]){ K-=mp[i]; ans=ans*mpow(i,mp[i])%MOD; } else{ ans=ans*mpow(i,K)%MOD; K-=mp[i]; break; } } } if(K>0) printf("-1\n"); else printf("%lld\n",ans); return 0; }