• 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
    ",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分

    代码的这个做法值得学习

  • 相关阅读:
    设计模式学习笔记之命令模式
    JavaEE复习三
    ubuntu下安装UltraEdit
    转载:Ubuntu下deb包的安装方法
    查看linux系统版本是32位还是64位
    手动编译生成apk
    android service文章转载
    @+android:id的一些记录
    android Tweened Animations
    ubuntu下打开chm文件
  • 原文地址:https://www.cnblogs.com/wawawa8/p/9403921.html
Copyright © 2020-2023  润新知