1. 程式人生 > >P2375 動物園

P2375 動物園

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 動物園