bzoj3670動物園【NOI2014】
Description
近日,園長髮現動物園中好吃懶做的動物越來越多了。例如企鵝,只會賣萌向遊客要吃的。為了整治動物園的不良風氣,讓動物們憑自己的真才實學向遊客要吃的,園長決定開設演算法班,讓動物們學習演算法。
某天,園長給動物們講解KMP演算法。
園長:“對於一個字串S,它的長度為L。我們可以在O(L)的時間內,求出一個名為next的陣列。有誰預習了next陣列的含義嗎?”
熊貓:“對於字串S的前i個字元構成的子串,既是它的字尾又是它的字首的字串中(它本身除外),最長的長度記作next[i]。”
園長:“非常好!那你能舉個例子嗎?”
熊貓:“例S為abcababc,則next[5]=2。因為S的前5個字元為abcab
園長表揚了認真預習的熊貓同學。隨後,他詳細講解了如何在O(L)的時間內求出next陣列。
下課前,園長提出了一個問題:“KMP演算法只能求出next陣列。我現在希望求出一個更強大num陣列一一對於字串S的前i個字元構成的子串,既是它的字尾同時又是它的字首,並且該字尾與該字首不重疊,將這種字串的數量記作num[i]。例如S為aaaaa,則num[4]
= 2
最後,園長給出了獎勵條件,第一個做對的同學獎勵巧克力一盒。聽了這句話,睡了一節課的企鵝立刻就醒過來了!但企鵝並不會做這道題,於是向參觀動物園的你尋求幫助。你能否幫助企鵝寫一個程式求出num陣列呢?
特別地,為了避免大量的輸出,你不需要輸出num[i]分別是多少,你只需要輸出對1,000,000,007取模的結果即可。
Input
第1行僅包含一個正整數n ,表示測試資料的組數。隨後n行,每行描述一組測試資料。每組測試資料僅含有一個字串S,S的定義詳見題目描述。資料保證S 中僅含小寫字母。輸入檔案中不會包含多餘的空行,行末不會存在多餘的空格。
Output
包含 n 行,每行描述一組測試資料的答案,答案的順序應與輸入資料的順序保持一致。對於每組測試資料,僅需要輸出一個整數,表示這組測試資料的答案對 1,000,000,007 取模的結果。輸出檔案中不應包含多餘的空行。
先用kmp求出最大匹配,順便記下該位置的前後綴匹配個數。
求解時,對每個位置一直求next,直到滿足字首長度不超過一半。
#include<cstdio>
#include<cstring>
char s[1000010];
int cnt[1000010],next[1000010];
long long ans;
const long long md=1000000007;
int main()
{
int i,j,k,l,m,n,p,q,x,y,z,T;
scanf("%d",&T);
while (T--)
{
memset(cnt,0,sizeof(cnt));
memset(next,0,sizeof(next));
scanf("%s",s+1);
l=strlen(s+1);
cnt[1]=1;
for (i=2,j=0;i<=l;i++)
{
while (j&&s[j+1]!=s[i]) j=next[j];
if (s[j+1]==s[i]) j++;
next[i]=j;
cnt[i]=cnt[j]+1;
}
ans=1;
for (i=2,j=0;i<=l;i++)
{
while (j&&s[j+1]!=s[i]) j=next[j];
if (s[j+1]==s[i]) j++;
while (j*2>i) j=next[j];
ans*=cnt[j]+1;
ans%=md;
}
printf("%lld\n",ans);
}
}