P2375 動物園
阿新 • • 發佈:2018-06-30
ios Go fail for size printf () href CP
入口
題目的大意就是輸出以任意一個字符結尾,既是前綴,又是後綴,且長度不超過總長度的一半的方案書的乘積。
考慮使用kmp
在處理失配數組的同時,處理出來以每個字符結尾的時的,能有多少個前綴和後綴相同的數量。
然後在進行一次類似kmp的匹配,在這次匹配中處理出來答案。
先是為什麽要處理多少個前綴和後綴相同的數量。
比如說,b是a的前綴和後綴,c是b的前綴和後綴(都合法)
然後c也肯定是a的前綴和後綴。處理出這個數組來,我們在尋求答案是只需要找到第一個符合條件的前綴&&後綴。加上我們預處理的個數就可以了。
//50分
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
char data[1010000];
int fail[1010000];
int num[1010000];
int main()
{ int m;
scanf("%d",&m);
while(m--)
{
scanf("%s",data);
memset(fail,0,sizeof(fail));
memset(num,0,sizeof(num));
int len=strlen(data)-1;
int k=0;num[1]=1;
for(int i=1;i<=len;i++)
{
while(k&&data[i]!=data[k])
k=fail[k];
if(data[i]==data[k]) fail[i+1]=++k;
num[i+1]=num[k]+1;
}
long long ans=1;
const long long mode=1e9+7;
for(int i=1;i<=len+1;i++)
{
k=i;
while((k<<1)>i)
k=fail[k];
ans=(ans*(num[k]+1))%mode;
}
printf("%lld\n",ans);
}
}
這是每次暴力從尾利用失配數組暴力蹦跶。
然後我們考慮加速一波。
每次從當前尾部暴力蹦跶肯定不行,我們考慮一下加速。
我們再一次利用類似kmp的方法。
因為我們每次只向後推一位結尾。
我們就可以利用上一次失配指針的位置,進行轉移。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
char data[1000010];
int fail[1000010];
int num[1000010];
const long long mode=1e9+7;
int main()
{
int m;scanf("%d",&m);
while(m--)
{
memset(fail,0,sizeof(fail));
memset(num,0,sizeof(num));
scanf("%s",data);
int len=strlen(data)-1;
int k=0;num[1]=1;
for(int i=1;i<=len;i++)
{
while(k&&data[i]!=data[k]) k=fail[k];
if(data[i]==data[k]) fail[i+1]=++k;
num[i+1]=num[k]+1;
}
k=0;
long long ans=1;
for(int i=1;i<=len+1;i++)
{
while(k&&data[i]!=data[k]) k=fail[k];
while((k<<1)>=i)
k=fail[k];
if(data[i]==data[k]) ++k;
ans=(ans*(num[k]+1))%mode;
}
printf("%lld\n",ans);
}
}
P2375 動物園