【BZOJ3670】动物园(KMP算法)
【BZOJ3670】动物园(KMP算法)
题面
题解
神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算法)的更多相关文章
- BZOJ-3670 动物园 KMP+奇怪的东西
YveH爷再刷KMP,DCrusher看他刷KMP,跟着两个人一块刷KMP... 3670: [Noi2014]动物园 Time Limit: 10 Sec Memory Limit: 512 MB ...
- [NOI2014][bzoj3670] 动物园 [kmp+next数组应用]
题面 传送门 思路 首先,这题最好的一个地方,在于它给出的关于$next$的讲解实在是妙极......甚至可以说我的kmp是过了这道题以后才脱胎换骨的 然后是正文: 如何求$num$数组? 这道题的输 ...
- 初涉KMP算法
久仰字符串系列理论 KMP 讲解(引用自bzoj3670动物园) 某天,园长给动物们讲解KMP算法. 园长:“对于一个字符串S,它的长度为L.我们可以在O(L)的时间内,求出一个名为next的数组.有 ...
- 【BZOJ3670】【NOI2014】动物园(KMP算法)
[BZOJ3670]动物园(KMP算法) 题面 BZOJ 题解 神TM阅读理解题 看完题目之后 想暴力: 搞个倍增数组来跳\(next\) 每次暴跳\(next\) 复杂度\(O(Tnlogn)\) ...
- BZOJ3670:[NOI2014]动物园(KMP)
Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习 ...
- 【BZOJ3670】【NOI2014】动物园 [KMP][倍增]
动物园 Time Limit: 10 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 近日,园长发现动物园中好吃懒做的动物 ...
- bzoj3670 [Noi2014]动物园——KMP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3670 第一次写KMP算法...又T又WA了半天... 1. num 数组表示包括其本身的前缀 ...
- uoj #5. 【NOI2014】动物园 kmp
#5. [NOI2014]动物园 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/5 Description 近日 ...
- bzoj 3670 动物园 - kmp - 动态规划
Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习 ...
随机推荐
- Spring bean的生命周期详解
bean的生命周期1.实例化bean 即new2.按照spring上下文对实例化的bean进行配置 即填充属性,也就是IOC/DI(控制反转,依赖注入)3.如果这个bean实现了BeanNameAwa ...
- python学习:字典排序
按字典值排序 按照字典value排序,类似sort -k 命令 import operator x= {1:2,3:4,4:3,2:1,0:0} sorted_x = sorted(x.ite ...
- [记录]Shell中的getopts和getopt用法
Shell中的getopts和getopt用法 1.getopts getopts(shell内置命令)不能直接处理长的选项(如:--prefix=/home等),getopts有两个参数,第一个参数 ...
- Mysql引擎中MyISAM和InnoDB的区别有哪些?
简单的概括一下 InnoDB:支持事务处理等不加锁读取支持外键支持行锁不支持FULLTEXT类型的索引不保存表的具体行数,扫描表来计算有多少行DELETE 表时,是一行一行的删除InnoDB 把数据和 ...
- javascript正则表达式的一些笔记
正则表达式:Regular Expression.使用单个字符串来描述,匹配一系列符合某个句法规则的字符串.即按照某种规则去匹配符合条件的字符串.正则表达式就是规则. \b 单词边界 regexp对象 ...
- Minikube之Win10单机部署
Kubernetes(k8s)是自动化容器操作的开源平台,基于这个平台,你可以进行容器部署,资源调度和集群扩容等操作.如果你曾经用过Docker部署容器,那么可以将Docker看成Kubernetes ...
- python内置函数-compile()
python的内置函数 compile()--编译. 这个函数有什么用呢? 一个最简单的例子, 就是我们的代码, 会被解释器读取,解释器读取后的其实是字符串, 然后通过compile编译后, 又转换成 ...
- nignx笔记1
上图是单版的架构,理论一个tomcat并发就200到300,经过优化后的最多500,这很明显容量低,而且出现单点故障后应用服务就不可以访问了,比如tomcat,这样明显对于多并发是不行的. 那么如果我 ...
- orcale和hive常用函数对照表(?代表未证实)
函数分类 oracle hive 说明 字符函数 upper('coolszy') upper(string A) ucase(string A) 将文本字符串转换成字母全部大写形式 lower('K ...
- swift 学习之自动引用计数
swift 学习之自动引用计数 学习和研究的主要是"实例对象和实例对象直接的相会强引用所产生的内从泄漏"和"使用闭包产生的强引用造成的内存泄漏" 注意:只有以引 ...