• 【bzoj3670】: [Noi2014]动物园 字符串-kmp-倍增


    【bzoj3670】: [Noi2014]动物园

    一开始想的是按照kmp把fail算出来的同时就可以递推求出第i位要f次可以跳到-1

    然后把从x=i开始顺着fail走,走到fail[x]*2<i 然后ans*=f[fail[x]]+1 就好了?

    但是发现显然会变成O(n^2) TLE。。

    于是就想到了倍增fail[i][j]就是第i位顺着fail 跳了 2^j 的位置

    好像很对的样子就把O(nlogn)的交了一发好像还是TLE了。。

    我可能需要W(卡)Y(常)S(数) 优化。。把fail[i][j] 换成 第j位顺着fail跳了2^i 次

    似乎一下快了好多 然后4s AC了。。

     1 /* http://www.cnblogs.com/karl07/ */
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <cstdio>
     7 using namespace std;
     8 
     9 #define P 1000000007
    10 int T,fail[21][1000005],num,f[1000005],Fail[1000005];
    11 char s[1000005];
    12 long long ans;
    13 
    14 void work(){
    15     scanf("%s",s+1);
    16     f[0]=0,Fail[0]=-1,ans=1; 
    17     for (int i=0;i<=20;i++) fail[i][0]=-1;
    18     for (int i=1,l=strlen(s+1);i<=l;i++){
    19         Fail[i]=Fail[i-1];
    20         while (s[Fail[i]+1]!=s[i] && Fail[i]!=-1) Fail[i]=Fail[Fail[i]];
    21         fail[0][i]=++Fail[i];
    22         for (int j=1;j<=20;j++) fail[j][i]= fail[j-1][i]==-1 ? -1 : fail[j-1][fail[j-1][i]];
    23         num=fail[0][i];
    24         for (int j=20;j>=0;j--) fail[j][num]*2>i ? num=fail[j][num] : 0;
    25         if (num!=0 && num*2>i) num=fail[0][num];
    26         f[i]=f[Fail[i]]+1;
    27         ans=(ans*(f[num]+1))%P;
    28     }
    29     printf("%lld
    ",ans);
    30 }
    31 
    32 int main(){
    33     scanf("%d
    ",&T);
    34     while (T--) work(); 
    35     return 0;
    36 }
    奇怪的倍增

    然后发现正解是维护fail1和fail2。。fail1一个是原来的fail,fail2[x]是fail1[x]跳到fail[x]*2<i的结果

    其实fail2可以跟着fail1一起递推,初始值换一下就好了。。

     1 /* http://www.cnblogs.com/karl07/ */
     2 #include <cstdlib>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <cstdio>
     7 using namespace std;
     8 
     9 #define P 1000000007
    10 int T,fail[1000005],num,f[1000005],Fail[1000005];
    11 char s[1000005];
    12 long long ans;
    13 
    14 void work(){
    15     scanf("%s",s+1);
    16     f[0]=0,Fail[0]=fail[0]=-1,ans=1; 
    17     for (int i=1,l=strlen(s+1);i<=l;i++){
    18         Fail[i]=Fail[i-1];
    19         fail[i]=fail[i-1];
    20         while (s[Fail[i]+1]!=s[i] && Fail[i]!=-1) Fail[i]=Fail[Fail[i]];
    21         while (s[fail[i]+1]!=s[i] && fail[i]!=-1) fail[i]=Fail[fail[i]];
    22         ++Fail[i];
    23         ++fail[i];
    24         while (fail[i]*2>i) fail[i]=Fail[fail[i]];
    25         f[i]=f[Fail[i]]+1;
    26         ans=(ans*(f[fail[i]]+1))%P;    
    27     }
    28     printf("%lld
    ",ans);
    29 }
    30 
    31 int main(){
    32     scanf("%d
    ",&T);
    33     while (T--) work(); 
    34     return 0;
    35 }
    正解
  • 相关阅读:
    二叉搜索树的后序遍历序列(python)
    从上往下打印二叉树(python)
    仿 PS中的颜色填充工具
    噪点图
    另一种噪点图 (有点类似卫星云图)
    像素融解
    比较位图差异
    颜色变换
    像素拷贝及赋值
    使用(模糊)滤镜
  • 原文地址:https://www.cnblogs.com/karl07/p/6659618.html
Copyright © 2020-2023  润新知