zoukankan      html  css  js  c++  java
  • 【BZOJ 3620】 3620: 似乎在梦中见过的样子 (KMP)

    3620: 似乎在梦中见过的样子

    Time Limit: 15 Sec  Memory Limit: 128 MB
    Submit: 755  Solved: 445

    Description

    “Madoka,不要相信 QB!”伴随着 Homura 的失望地喊叫,Madoka 与 QB 签订了契约.
    这是 Modoka 的一个噩梦,也同时是上个轮回中所发生的事.为了使这一次 Madoka 不再与 QB签订契约,Homura 决定在刚到学校的第一天就解决 QB.然而,QB 也是有许多替身的(但在第八话中的剧情显示它也有可能是无限重生的),不过,意志坚定的 Homura 是不会放弃的——她决定
    消灭所有可能是 QB 的东西.现在,她已感受到附近的状态,并且把它转化为一个长度为 n 的字符串交给了学 OI 的你.
    现在你从她的话中知道 , 所有形似于 A+B+A 的字串都是 QB 或它的替身 , 且len(A)>=k,len(B)>=1 (位置不同其他性质相同的子串算不同子串,位置相同但拆分不同的子串算同一子串),然后你必须尽快告诉 Homura 这个答案——QB 以及它的替身的数量.

    Input

    第一行一个字符串,第二行一个数 k

    Output

    仅一行一个数 ans,表示 QB 以及它的替身的数量

    Sample Input

    【样例输入 1】
    aaaaa
    1
    【样例输入 2】
    abcabcabc
    2

    Sample Output

    【样例输出 1】
    6

    【样例输出 2】
    8

    HINT

    对于 100%的数据:n<=15000 , k<=100,且字符集为所有小写字母

    Source

    【分析】

      做这题的时候并不知道资瓷N^2的KMP。。。

      其实N^2的KMP还挺容易打错的,因为根节点不能是0,是st-1。中间有几个判断都要注意。

      直接枚举起点。然后做一遍KMP。

      询问的时候看看nt是否符合。首先要长于k,其次不能相交且要空出一个位置。

      假设前后缀匹配部分长度是p,枚举到右端点为j。

      则2*p<j-i+1,p>=k

      p一开始是nt,然后一直nt。但是这样暴就O(n^3)了会超时的。

      用一个g数组记录,他到他的nt中,p大于等于k的最小值即可。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 #define Maxn 15010
     8 #define INF 0xfffffff
     9 
    10 char s[Maxn];
    11 int l,k,nt[Maxn],g[Maxn];
    12 
    13 void KMP(int st)
    14 {
    15     nt[st]=st-1;g[st-1]=INF;
    16     g[st]=k==1?1:INF;
    17     for(int p=st-1,i=st+1;i<=l;i++)
    18     {
    19         while(s[i]!=s[p+1]&&p>=st) p=nt[p];
    20         if(s[i]==s[p+1]) p++;
    21         nt[i]=p;
    22         g[i]=INF;
    23         if(i-st+1>=k) g[i]=i-st+1;
    24         g[i]=min(g[i],g[nt[i]]);
    25     }
    26 }
    27 
    28 int ans=0;
    29 void ffind(int st)
    30 {
    31     KMP(st);
    32     for(int i=st;i<=l;i++)
    33     {
    34         if(2*g[nt[i]]<i-st+1) ans++;
    35     }
    36 }
    37 
    38 int main()
    39 {
    40     scanf("%s",s+1);l=strlen(s+1);
    41     scanf("%d",&k);
    42     for(int i=1;i<=l;i++) ffind(i);
    43     printf("%d
    ",ans);
    44     return 0;
    45 }
    View Code

    2017-04-25 11:48:23

  • 相关阅读:
    一些关于视频相关基础概念
    熟悉某项目代码---零碎小知识总结
    C#中如何判断一个字符是汉字
    面试碰到一个这样的题------ 输入为一个字符串和字节数,输出为按字节截取的字符串
    C# 拼Json格式字符串 返回前段js 出错解决
    学习maple
    格林公式
    麦克斯韦方程组 (Maxwell's equation)的简单解释
    关于Ciarlet的泛函的一道homework的一个想法
    关于分开编写多个LaTeX文件的一点微小的总结
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6761260.html
Copyright © 2011-2022 走看看