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分

代码的这个做法值得学习

 

posted @ 2018-08-01 21:04  wawawa8  阅读(143)  评论(0编辑  收藏  举报