【BZOJ3670】【NOI2014】动物园(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】【NOI2014】动物园(KMP算法)的更多相关文章
- BZOJ3670:[NOI2014]动物园(KMP)
Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习 ...
- bzoj3670 [Noi2014]动物园——KMP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3670 第一次写KMP算法...又T又WA了半天... 1. num 数组表示包括其本身的前缀 ...
- BZOJ3670 [Noi2014]动物园 【KMP计数】
3670: [Noi2014]动物园 Time Limit: 10 Sec Memory Limit: 512 MB Submit: 3143 Solved: 1690 [Submit][Stat ...
- [BZOJ3670] [NOI2014] 动物园 解题报告 (KMP)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3670 Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅, ...
- bzoj千题计划250:bzoj3670: [Noi2014]动物园
http://www.lydsy.com/JudgeOnline/problem.php?id=3670 法一:KMP+st表 抽离nxt数组,构成一棵树 若nxt[i]=j,则i作为j的子节点 那么 ...
- BZOJ3670 [Noi2014]动物园
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- BZOJ 3670: [Noi2014]动物园 [KMP]
求这玩意: 对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i] 对1,000,000,007取模的结果 n≤5,L≤1,00 ...
- [NOI2014]动物园(kmp)
题目 https://www.luogu.org/problemnew/show/P2375 做法 查找多少个前缀与后缀配对,其实就是\(fail\)树的深度 而不可重叠,其实\(i\)不可用的,\( ...
- BZOJ 3670 NOI2014 动物园 KMP+dp
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3670 题意概述:令num[i]表示字符串由1~i的字符形成的前缀中不相重叠的相同前后缀的数 ...
- P2375 [NOI2014]动物园 KMP
好,暴力能拿$50pts\space qwq$ 暴力的思路就是一直跳$nxt[j]$,直到它的长度小于串的一半,然后开始计数,当然要接着跳$nxt[j]$ 正解:考虑没有长度要求的(不要求不重合)公共 ...
随机推荐
- 【WPF】两则动画效果
原文:[WPF]两则动画效果 引言 利用WPF的动画可以轻而易举的实现各种各样的特效,如擦除,滑动进入等,先看两个效果图 第一个效果 这个动画其实利用了OpacityMask和LinearGradie ...
- python3 str或bytes转换函数
str或bytes始终返回为str #!/usr/bin/env python # -*- coding: utf-8 -*- def to_str(bytes_or_str): if isinsta ...
- JVM技术周报第2期
JVM技术周报第2期 JVM技术周报分享JVM技术交流群的讨论内容,由群内成员整理归纳而成.如果你有兴趣入群讨论,请关注「Java技术精选」公众号,通过右下角菜单「入群交流」加我好友,获取入群详情. ...
- identityServer4 中的概念(Scope,claim)
在IdentityServer中好多地方出现这几个词,这单词的解释也有好多大神解释过: chaim: ASP.NET Core 之 Identity 入门(一),这个是asp.net identity ...
- js的各种正则表达式
验证各种手机包括成都"028-"开头的座机号验证 if (!(/^(16[8]|13[0-9]|15[0|3|6|7|8|9]|18[7])\d{8}|(028-)\d{7}$/. ...
- 阿里云ECS 固定带宽变为按量付费的方式
阿里云ECS 固定带宽变为按量付费的方式 阿里云控制台 2.升降配置-降低配置-降低至最低配置 3.为按量带宽设置一个峰值,例如100M. 4.过几分钟,就自动变为按量付费的带宽了.
- 将WebService部署到 SharePoint 2010 gac 缓存中,并用Log4Net记录日志到数据库
最近做了一个sharePoint项目,需要实现的功能是,第三方网站访问我们sharePoint中的数据,通过Webservice方式实现文件的上传和下载. 于是代码工作完成了之后,本地调试没什么问题, ...
- Jenkins下载安装
Jenkins是什么? Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,无论用的是什么平台.这是一个免费的源代码,可以处理任何类型的构建或持续集成.集成Jenkins可以用于一些测 ...
- Unity插件-NGUI学习笔记
Anchors 的作用 类似Android里面的.9格式图片的功能, 边框可以随着文字变大而变大. 实现方法: 用NGUI 创建一个Sprite, 命名为TextBg, 一个Label, Label的 ...
- PAT甲题题解-1001. A+B Format (20)-字符串处理,水
计算A+B的和,并且按标准格式处理,每3个就要有个逗号 #include <iostream> #include <cstdio> #include <algorithm ...