bzoj 3670 [Noi2014]动物园
题面
https://www.lydsy.com/JudgeOnline/problem.php?id=3670
题解
先用kmp求出串的next数组
对于一个i来说:
首先找到最大的满足条件的j
然后j是可行的,next[j]也是可行的,next[next[j]]也是可行的,……
并且可行的只有这些
原因:
所以我们只要建出next树 并且找到一个点在树上的深度就可以了
问题在于怎么找到最大的j
首先不难发现假设对于i来说,最大的j为$j_0$
那么对于i+1来说,最大的j不会超过$j_0+1$
所以可以用代码中的写法求得j
Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 ll read(){ 6 ll x=0,f=1;char c=getchar(); 7 while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();} 8 while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();} 9 return x*f; 10 } 11 12 const int mod=1e9+7; 13 int tc; 14 char s[1000100]; 15 int f[1000100]; 16 int dep[1000100]; 17 18 void work(){ 19 scanf("%s",&s[1]); 20 int n=strlen(s+1); 21 f[0]=-1; 22 int p=0; 23 ll ans=1; 24 for(int i=1;i<=n;i++){ 25 int j=f[i-1]; 26 while(j!=-1 && s[i]!=s[j+1]) j=f[j]; 27 f[i]=j+1; 28 dep[i]=dep[f[i]]+1; 29 while(p!=-1 && (s[p+1]!=s[i]||p+1>i>>1)) p=f[p]; 30 ans=ans*(dep[++p]+1)%mod; 31 } 32 printf("%lld\n",ans); 33 } 34 35 int main(){ 36 #ifdef LZT 37 freopen("in","r",stdin); 38 #endif 39 tc=read(); 40 while(tc--) 41 work(); 42 return 0; 43 }
Review
动机?
首先求next数组是肯定的
然后画一画图就可以发现需要建一棵next树
但是我没有想到一个快速求j的方法
我的做法是 记录fa[i][k]表示在next树上,i的$2^k$层的父亲是谁
然后对于一个i,沿着fa一直找,直到找到一个小于等于i/2的值,就是j
但是这样多一个log 只能得到80分
代码的这个做法值得学习