[回文树][BZOJ2160][国家集训队]拉拉队排练

题面

Description

艾利斯顿商学院篮球队要参加一年一度的市篮球比赛了。拉拉队是篮球比赛的一个看点,好的拉拉队每每能帮助球队增长士气,赢得最终的比赛。因此做为拉拉队队长的楚雨荨同窗知道,帮助篮球队训练好拉拉队有多么的重要。拉拉队的选拔工做已经结束,在雨荨和校长的挑选下,\(n\)位集优秀的身材、舞技于一体的美女从众多报名的女生中脱颖而出。这些女生将随着篮球队的小伙子们一块儿,和对手抗衡,为艾利斯顿篮球队加油助威。一个阳光明媚的早晨,雨荨带领拉拉队的队员们开始了排练。\(n\)个女生从左到右排成一行,每一个人手中都举了一个写有\(26\)个小写字母中的某一个的牌子,在比赛的时候挥舞,为小伙子们呐喊、加油。雨荨发现,若是连续的一段女生,有奇数个,而且他们手中的牌子所写的字母,从左到右和从右到左读起来同样,那么这一段女生就被称做和谐小群体。如今雨荨想找出全部和谐小群体,而且按照女生的个数降序排序以后,前\(K\)个和谐小群体的女生个数的乘积是多少。因为答案可能很大,雨荨只要你告诉她,答案除以\(19930726\)的余数是多少就好了。ios

Input

输入为标准输入。第一行为两个正整数\(n\)\(K\),表明的东西在题目描述中已经叙述。接下来一行为\(n\)个字符,表明从左到右女生拿的牌子上写的字母。测试

Output

输出为标准输出。输出一个整数,表明题目描述中所写的乘积除以\(19930726\)的余数,若是总的和谐小群体个数小于\(K\),输出一个整数\(-1\)spa

Sample Input

5 3
ababa

Sample Output

45

样例说明

和谐小群体女生所拿牌子上写的字母从左到右按照女生个数降序排序后为\(ababa\), \(aba\), \(aba\), \(bab\), \(a\), \(a\), \(a\), \(b\), \(b\),前三个长度的乘积为\(5\times3\times3=45\)指针

Hint

总共20个测试点,数据范围知足:code

测试点 \(n\) \(K\)
1 \(\le10\) \(\le10\)
2 \(\le100\) \(\le100\)
3 \(\le100\) \(\le100\)
4 \(\le1,000\) \(\le1,000\)
5 \(\le1,000\) \(\le1,000\)
6 \(\le1,000\) \(\le1,000\)
7 \(\le1,000\) \(\le1,000\)
8 \(\le100,000\) \(=1\)
9 \(\le100,000\) \(\le100,000\)
10 \(\le100,000\) \(\le100,000\)
11 \(\le100,000\) \(\le100,000\)
12 \(\le100,000\) \(\le1,000,000,000,000\)
13 \(\le100,000\) \(\le1,000,000,000,000\)
14 \(\le100,000\) \(\le1,000,000,000,000\)
15 \(\le500,000\) \(\le1,000,000,000,000\)
16 \(\le500,000\) \(\le1,000,000,000,000\)
17 \(\le500,000\) \(\le1,000,000,000,000\)
18 \(\le1,000,000\) \(=1\)
19 \(\le1,000,000\) \(\le1,000,000\)
20 \(\le1,000,000\) \(\le1,000,000,000,000\)

分析

这道题比较特殊,只要奇数长的回文串,并且须要全部的回文串,而Manacher须要利用以前的结果,所以不方便求出全部回文串,不然就和暴力无本质区别了。排序

这个时候,咱们就须要一个更强大的武器:回文树(回文自动机)
ip

其实这就是AC自动机+回文串。图中的\(next\)指针即trie中的儿子,只不过是从两边添加。而\(fail\)指针则是AC自动机中的失配指针,能够用于查询。系列操做与AC自动机并没有过多差异,具体请见代码。get

回文串求出来了,可怎么查询呢?一看\(K\)的大小,就知道不能所有存储。因此以长度为下标存储便可。接着枚举长度,用快速幂计算结果。input

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll mod=19930726;
ll lenx[1000001],tas;
class PAM{
    private:
        int nxt[1000001][26],fail[1000001],len[1000001],s[1000001],lst,tot,n;
        ll cnt[1000001];
        int newn(int lg){
            len[tot]=lg;
            return tot++;
        }
        int getf(int u){
            while(s[n-len[u]-1]!=s[n])u=fail[u];
            return u;
        }
    public:
        void init(){
            memset(nxt,0,sizeof(nxt));
            lst=tot=n=0;
            newn(0);
            newn(-1);
            s[0]=-1;
            fail[0]=1;
        }
        void add(char c){
            s[++n]=c-'a';
            int cur=getf(lst);
            if(!nxt[cur][c-'a']){
                int u=newn(len[cur]+2);
                fail[u]=nxt[getf(fail[cur])][c-'a'];
                nxt[cur][c-'a']=u;
            }
            lst=nxt[cur][c-'a'];
            cnt[lst]++;
        }
        void cont(){
            for(int i=tot-1;i>=0;i--)cnt[fail[i]]+=cnt[i];
            for(int i=2;i<tot;i++){
                if(len[i]&1){
                    lenx[len[i]]+=cnt[i];
                    tas+=cnt[i];
                }
            }
        }
}pam;
ll fastpow(ll x,ll p){
    ll ans=1;
    while(p){
        if(p&1)ans=ans*x%mod;
        x=x*x%mod;
        p>>=1;
    }
    return ans;
}
char str[1000001];
int main(){
    ll n,k,ans=1;
    scanf("%lld%lld",&n,&k);
    scanf("%s",str);
    pam.init();
    for(int i=0;i<n;i++)pam.add(str[i]);
    pam.cont();
    if(k>tas){printf("-1\n");return 0;}
    for(int i=n;i>=1&&k;i--){
        ans=ans*fastpow(i,min(lenx[i],k))%mod;
        k=max(k-lenx[i],0LL);
    }
    printf("%lld\n",ans);
}
相关文章
相关标签/搜索