【BZOJ3670】动物园(KMP算法)

题面

BZOJ

题解

神TM阅读理解题

看完题目之后

想暴力:

搞个倍增数组来跳\(next\)

每次暴跳\(next\)

复杂度\(O(Tnlogn)\)

算一下,感觉复杂度差不多呀

很果断的交了一发

然后\(80\)分。。。

暴力代码送上:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MOD 1000000007
char s[1200000];
int nt[1200000];
int jp[1200000][21];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",s+1);
nt[1]=0;
int l=strlen(s+1);
for(int i=2;i<=l;++i)
{
int j=nt[i-1];
while(j&&s[i]!=s[j+1])j=nt[j];
if(s[i]==s[j+1])nt[i]=j+1;
else nt[i]=0;
jp[i][0]=nt[i];
}
for(int j=1;j<20;++j)
for(int i=1;i<=l;++i)
jp[i][j]=jp[jp[i][j-1]][j-1];
int ans=1;
for(int i=2;i<=l;++i)
{
int tt=i;
for(int j=19;j>=0;--j)
if(jp[tt][j]*2>i)tt=jp[tt][j];
int gg=0;
for(int j=19;j>=0;--j)
if(jp[tt][j])gg+=1<<j,tt=jp[tt][j];
ans=1ll*ans*(gg+1)%MOD;
}
printf("%d\n",ans);
}
return 0;
}

然后我很不爽

把倍增数组的两维反了过来,防止反复横跳

然后我就\(AC\)了???

又一次感受到玄学强大的力量

这个\(O(Tnlogn)\)的复杂度果然很对呀。。。

暴力能AC???:

(BZOJ上都能AC???)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MOD 1000000007
char s[1200000];
int nt[1200000];
int jp[21][1200000];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",s+1);
nt[1]=0;
int l=strlen(s+1);
for(int i=2;i<=l;++i)
{
int j=nt[i-1];
while(j&&s[i]!=s[j+1])j=nt[j];
if(s[i]==s[j+1])nt[i]=j+1;
else nt[i]=0;
jp[0][i]=nt[i];
}
for(int j=1;j<20;++j)
for(int i=1;i<=l;++i)
jp[j][i]=jp[j-1][jp[j-1][i]];
int ans=1;
for(int i=2;i<=l;++i)
{
int tt=i;
for(int j=19;j>=0;--j)
if(jp[j][tt]*2>i)tt=jp[j][tt];
int gg=0;
for(int j=19;j>=0;--j)
if(jp[j][tt])gg+=1<<j,tt=jp[j][tt];
ans=1ll*ans*(gg+1)%MOD;
}
printf("%d\n",ans);
}
return 0;
}

经历了这么滑稽的事情

还是想想有没有更加好的复杂度。。。

考虑记录一个数组\(cnt[i]\)

表示从\(i\)位置最多能够往前跳的次数

很明显的,\(cnt[i]=cnt[next[i]]+1\)

现在,我们只需要知道每一个位置能够跳到哪里就行了

还是最简单的暴力

每次从当前位置\(i\)开始,暴力向前跳到\(k\)

直到\(k*2<i\)为止,然后答案累乘\(cnt[k]+1\)

看起来每次暴跳的时间复杂度不太能够接受

最坏可以打到\(O(n^2)\)

但是考虑\(next\)数组是怎么求出来的

每次沿着前一个字符的\(next\)跳

直到找到一个合法的位置

因此,我们模仿这个过程

假设上一个字符跳到了\(k\)

那么,当前位置最多跳到\(k+1\)

很容易证明

假设当前位置跳到了一个合法的位置\(k'\)

那么,当前位置的前一个位置,必定可以跳到一个合法位置\(k'-1\)

所以,我们只需要类似\(KMP\),每次利用上一次求出来的\(k\)接着跳就行了

这样的时间复杂度近似\(O(n)\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define rg register
#define MOD 1000000007
char s[1200000];
int nt[1200000];
int cnt[1200000];
int main()
{
rg int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",s+1);
nt[1]=0;
rg int l=strlen(s+1);
for(rg int i=2;i<=l;++i)
{
rg int j=nt[i-1];
while(j&&s[i]!=s[j+1])j=nt[j];
if(s[i]==s[j+1])nt[i]=j+1;
else nt[i]=0;
}
cnt[1]=1;
rg int ans=1;
for(rg int i=2;i<=l;++i)cnt[i]=cnt[nt[i]]+1;
for(rg int i=2,k=0;i<=l;++i)
{
while(k&&s[k+1]!=s[i])k=nt[k];
if(s[i]==s[k+1])k++;
while(k*2>i)k=nt[k];
ans=1ll*ans*(cnt[k]+1)%MOD;
}
printf("%d\n",ans);
}
return 0;
}

【BZOJ3670】动物园(KMP算法)的更多相关文章

  1. BZOJ-3670 动物园 KMP+奇怪的东西

    YveH爷再刷KMP,DCrusher看他刷KMP,跟着两个人一块刷KMP... 3670: [Noi2014]动物园 Time Limit: 10 Sec Memory Limit: 512 MB ...

  2. [NOI2014][bzoj3670] 动物园 [kmp+next数组应用]

    题面 传送门 思路 首先,这题最好的一个地方,在于它给出的关于$next$的讲解实在是妙极......甚至可以说我的kmp是过了这道题以后才脱胎换骨的 然后是正文: 如何求$num$数组? 这道题的输 ...

  3. 初涉KMP算法

    久仰字符串系列理论 KMP 讲解(引用自bzoj3670动物园) 某天,园长给动物们讲解KMP算法. 园长:“对于一个字符串S,它的长度为L.我们可以在O(L)的时间内,求出一个名为next的数组.有 ...

  4. 【BZOJ3670】【NOI2014】动物园(KMP算法)

    [BZOJ3670]动物园(KMP算法) 题面 BZOJ 题解 神TM阅读理解题 看完题目之后 想暴力: 搞个倍增数组来跳\(next\) 每次暴跳\(next\) 复杂度\(O(Tnlogn)\) ...

  5. BZOJ3670:[NOI2014]动物园(KMP)

    Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习 ...

  6. 【BZOJ3670】【NOI2014】动物园 [KMP][倍增]

    动物园 Time Limit: 10 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 近日,园长发现动物园中好吃懒做的动物 ...

  7. bzoj3670 [Noi2014]动物园——KMP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3670 第一次写KMP算法...又T又WA了半天... 1. num 数组表示包括其本身的前缀 ...

  8. uoj #5. 【NOI2014】动物园 kmp

    #5. [NOI2014]动物园 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/5 Description 近日 ...

  9. bzoj 3670 动物园 - kmp - 动态规划

    Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习 ...

随机推荐

  1. UML设计

    UML设计 1. UML的概念 Unified Modeling Language(UML)又称统一建模语言或标准建模语言,是一个支持模型化和软件系统开发的图形化语言.为软件开发的所有阶段提供模型化和 ...

  2. wangeditor Demo

    <html> <head> <!--在这里字符集的设定很重要,如果设定不当将会出现乱码--> <meta charset="UTF-8"& ...

  3. CENTOS6.6下mysql MMM架构搭建

    本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn MMM(Master-Master replication mana ...

  4. php 高并发下 秒杀处理思路

    1.用额外的单进程处理一个队列,下单请求放到队列里,一个个处理,就不会有并发的问题了,但是要额外的后台进程以及延迟问题,不予考虑. 2.数据库乐观锁,大致的意思是先查询库存,然后立马将库存+1,然后订 ...

  5. Java经典编程题50道之七

    输入一行字符,分别统计出其中英文字母.空格.数字和其它字符的个数. public class Example07 {    public static void main(String[] args) ...

  6. Linux常用命令详解(二) -- 查找常用命令

    locate:    作用:在后台数据库中按文件名搜索,搜索速度更快    命令格式:locate 文件名    选项或参数:            -l    num(要显示的行数)         ...

  7. 使用wireshark抓取TCP包分析1

    使用wireshark抓取TCP包分析1 前言 介绍 目的 准备工作 传输 创建连接 握手 生成密钥 发送数据 断开连接 结论 前言 介绍 本篇文章是使用wireshrak对某个https请求的tcp ...

  8. 箱型图boxplot函数的使用

    主要参数: medlwd:设置中位线宽度 whiskcol:设置虚线颜色 staplecol:设置顶端颜色 outcol:离群值颜色 相应的具体位置: outline=FALSE:去除离群值 outp ...

  9. Linux下添加自定义脚本到开机自启动,标准rpm,举例:设置Apache自启动

    写一个脚本,名字为:autostart.sh,放在/etc/init.d/目录下,赋予权限chmod +x /etc/init.d/autostart.sh 代码如下 #!/bin/sh #chkco ...

  10. Angular:利用内容投射向组件输入ngForOf模板

    现在,我们写一个组件puppiesListCmp,用于显示小狗狗的列表: //puppies-list.component.ts @Component({ selector: 'puppies-lis ...