[bzoj3670][Noi2014]動物園 KMP字符串匹配

Description

近日,園長髮現動物園中好喫懶做的動物越來越多了。例如企鵝,只會賣萌向遊客要喫的。爲了整治動物園的不良風氣,讓動物們憑自己的真才實學向遊客要喫的,園長決定開設算法班,讓動物們學習算法。

某天,園長給動物們講解KMP算法。

園長:“對於一個字符串S,它的長度爲L。我們可以在O(L)的時間內,求出一個名爲next的數組。有誰預習了next數組的含義嗎?”

熊貓:“對於字符串S的前i個字符構成的子串,既是它的後綴又是它的前綴的字符串中(它本身除外),最長的長度記作next[i]。”

園長:“非常好!那你能舉個例子嗎?”

熊貓:“例S爲abcababc,則next[5]=2。因爲S的前5個字符爲abcabab既是它的後綴又是它的前綴,並且找不到一個更長的字符串滿足這個性質。同理,還可得出next[1] = next[2] = next[3] = 0,next[4] = next[6] = 1,next[7] = 2,next[8] = 3。”

園長表揚了認真預習的熊貓同學。隨後,他詳細講解了如何在O(L)的時間內求出next數組。

下課前,園長提出了一個問題:“KMP算法只能求出next數組。我現在希望求出一個更強大num數組一一對於字符串S的前i個字符構成的子串,既是它的後綴同時又是它的前綴,並且該後綴與該前綴不重疊,將這種字符串的數量記作num[i]。例如S爲aaaaa,則num[4] = 2。這是因爲S的前4個字符爲aaaa,其中aaa都滿足性質‘既是後綴又是前綴’,同時保證這個後綴與這個前綴不重疊。而aaa雖然滿足性質‘既是後綴又是前綴’,但遺憾的是這個後綴與這個前綴重疊了,所以不能計算在內。同理,num[1] = 0,num[2] = num[3] = 1,num[5] = 2。”

最後,園長給出了獎勵條件,第一個做對的同學獎勵巧克力一盒。聽了這句話,睡了一節課的企鵝立刻就醒過來了!但企鵝並不會做這道題,於是向參觀動物園的你尋求幫助。你能否幫助企鵝寫一個程序求出num數組呢?

特別地,爲了避免大量的輸出,你不需要輸出num[i]分別是多少,你只需要輸出對1,000,000,007取模的結果即可。

Input

第1行僅包含一個正整數n ,表示測試數據的組數。隨後n行,每行描述一組測試數據。每組測試數據僅含有一個字符串S,S的定義詳見題目描述。數據保證S 中僅含小寫字母。輸入文件中不會包含多餘的空行,行末不會存在多餘的空格。

Output

包含 n 行,每行描述一組測試數據的答案,答案的順序應與輸入數據的順序保持一致。對於每組測試數據,僅需要輸出一個整數,表示這組測試數據的答案對 1,000,000,007 取模的結果。輸出文件中不應包含多餘的空行。

Sample Input

3
aaaaa
ab
abcababc

Sample Output

36
1
32

HINT

 

n≤5,L≤1,000,000

 

思維難度:NOIP+

代碼難度:NOIP

算法:KMP

 

#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
const int Maxn=1000005;
const ll mod=1000000007;
ll next[Maxn],num[Maxn],n,m,ans=1,fai[Maxn]; 
char a[Maxn],b[Maxn];
int main(){
    int t;
    scanf("%d\n",&t);
    while(t--){
        memset(num,0,sizeof(num));
        memset(next,0,sizeof(next));
        ans=1;
        scanf("%s\n",b+1);
        m=strlen(b+1);
        for(ll i=2,j=0;i<=m;i++){
            while(j&&b[j+1]!=b[i])j=next[j];
            if(b[j+1]==b[i])j++;
            next[i]=j;fai[j]=i;if(j)num[i]=num[j]+1;
        }
        for(ll i=2,j=0;i<=m;i++){
            while(j&&b[j+1]!=b[i])j=next[j];
            if(b[j+1]==b[i])j++;
            while((j<<1)>i){
                j=next[j];
            }
            if(j)ans=ans*(num[fai[j]]+1)%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章