【KMP】BZOJ3670-[Noi2014]动物园
【题目大意】
[依然借用别人的概括]给定一个长为L的字符串(L<=100W),求一个num数组,num[i]表示长度为i的前缀中字符串S’的数量,其中S‘既是该前缀的前缀也是该前缀的后缀,且|S'|*2<=i
【思路】
KMP中next数组的变形。先算一次next数组和dep数组,其中dep数组表示当前前缀经过j=next[j]可以到达-1,这个值其实就是num数组的雏形。然后再进行一次求解next数组,每次前缀不断进行j=next[j],直到满足|S'|*2<=i。此时的dep[j]就是当前前缀的num值,由于前一次求解next数组预处理,这个值可以在O(1)时间内求解。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define LL long long 6 #define mod 1000000007 7 const int MAXN=1000000+500; 8 using namespace std; 9 int n; 10 char p[MAXN]; 11 int next[MAXN],dep[MAXN],next2[MAXN]; 12 int len; 13 14 void getnext() 15 { 16 int i=0,j=-1; 17 next[i]=j; 18 dep[i]=0; 19 while (i<len) 20 { 21 if (j==-1 || p[i]==p[j]) 22 { 23 dep[++i]=dep[++j]+1; 24 next[i]=j; 25 } 26 else j=next[j]; 27 } 28 } 29 30 void getans() 31 { 32 LL ans=1; 33 int i=0,j=-1; 34 while (i<len) 35 { 36 if (j==-1 || p[i]==p[j]) 37 { 38 i++,j++; 39 while (j!=-1 && (j<<1)>i) 40 j=next[j]; 41 if (j!=-1 && i!=-1) ans=ans*(LL)(dep[j]+1) % mod; 42 } 43 else j=next[j]; 44 } 45 printf("%lld\n",ans); 46 47 48 } 49 50 int main() 51 { 52 scanf("%d",&n); 53 for (int i=0;i<n;i++) 54 { 55 scanf("%s",p); 56 len=strlen(p); 57 getnext(); 58 getans(); 59 } 60 return 0; 61 }