NOI 2014 動物園
阿新 • • 發佈:2021-07-12
NOI 2014 動物園
Solution:
\(Kmp\)的性質考察。
1.將i所包含的所有字首次數通過遞推統計出來,仔細觀察會有\(50\)分暴力跳\(Next\)的做法,跳到第一個\(pos*2<=i\)即可,但是理論複雜度過不去。
2.考慮先將i所包含的所有字首次數通過遞推統計出來,再做一遍求\(Next\)陣列的主過程,不過應繼續跳\(Next\),直至\(j*2<=i\)為止(仔細思考),時間複雜度不變,還是\(O(n+m)\)。
Code:
\(50\)分暴力跳\(Next\)程式碼
#include<bits/stdc++.h> using namespace std; const int N=2e6+10; char s[N]; int Next[N]; int dp[N]; const int mod=1e9+7; int n; int fail[N]; void get_next(char p[],int lenp){ int j=0; for(int i=2;i<=lenp;++i){ while(j&&p[j+1]!=p[i])j=Next[j]; if(p[j+1]==p[i])j++; Next[i]=j; fail[i]=fail[Next[i]]+1; } } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%s",s+1); int len=strlen(s+1); for(int i=0;i<=len;++i){ fail[i]=0; } fail[1]=1; get_next(s,len); long long sum=1; for(int i=1;i<=len;++i){ int pos=i; int f=0; while(pos*2>i){ pos=Next[pos]; } f=1; if(pos)sum=sum*(fail[pos]+f)%mod; } printf("%lld\n",sum); } return 0; }
正解程式碼
#include<bits/stdc++.h> using namespace std; const int N=2e6+10; char s[N]; int Next[N]; int dp[N]; const int mod=1e9+7; int n; int fail[N]; void get_next(char p[],int lenp){ int j=0; for(int i=2;i<=lenp;++i){ while(j&&p[j+1]!=p[i])j=Next[j]; if(p[j+1]==p[i])j++; Next[i]=j; fail[i]=fail[Next[i]]+1; } } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%s",s+1); int len=strlen(s+1); for(int i=0;i<=len;++i){ fail[i]=0; } fail[1]=1; get_next(s,len); long long sum=1; int j=0; for(int i=2;i<=len;++i){ while(j&&s[i]!=s[j+1])j=Next[j]; if(s[i]==s[j+1])j++; while(j*2>i){ j=Next[j]; } sum=sum*(fail[j]+1)%mod; } printf("%lld\n",sum); } return 0; }