【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. java递归

    package com.sun.test; import java.util.ArrayList; import java.util.List; /** * 递归 * */ public class ...

  2. Scrapy-简单介绍

    Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中. 其最初是为了 页面抓取 (更确切来说, 网络抓取 )所设计的, ...

  3. jquery toggle 方法被废除的替代方法

    今天使用 toggle 方法的时候,该方法一直不能生效. 原来jquery 的引入文件是1.9,该方法在1.8以上已被废除. 那么简单的切换状态,我们可使用if 语句进行代替 如下: 记录一开始设置隐 ...

  4. C# 使用 SmtpClient 发送邮件注意项

    最近有邮件发送需求,使用 C#  SmtpClient 对象发送邮件 , 报异常, 如下错误代码: 调整代码顺序后,发送邮件成功! 注意:一定要先设置 EnableSsl和UseDefaultCred ...

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

    判断101-200之间有多少个素数,并输出所有素数. public class Example02 {    public static void main(String[] args) {      ...

  6. Ubantu16.04 redis安装

    通过FTP方式将redis的安装包从windows上传到linux上 解压命令:$sudo tar -zxf ~/Downloads/redis-3.2.7.tar.gz -C /usr/local ...

  7. json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值

    一.json相关概念 json,全称为javascript object notation,是一种轻量级的数据交互格式.采用完全独立于语言的文本格式,是一种理想的数据交换格式. 同时,json是jav ...

  8. 《android开发艺术探索》读书笔记(十五)--Android性能优化

    接上篇<android开发艺术探索>读书笔记(十四)--JNI和NDK编程 No1: 如果<include>制定了这个id属性,同时被包含的布局文件的根元素也制定了id属性,那 ...

  9. UVA1213

    先打表,再回溯+剪枝 AC代码: #include<cstdio> #include<cstring> #include<cmath> const int maxn ...

  10. php的filesystem基本函数的学习(1)

    1.basename basename — 返回路径中的文件名部分 string basename ( string $path [, string $suffix ] ) 给出一个包含有指向一个文件 ...