[迴文樹][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);
}
相關文章
相關標籤/搜索