【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】【NOI2014】动物园(KMP算法)的更多相关文章

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

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

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

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

  3. BZOJ3670 [Noi2014]动物园 【KMP计数】

    3670: [Noi2014]动物园 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 3143  Solved: 1690 [Submit][Stat ...

  4. [BZOJ3670] [NOI2014] 动物园 解题报告 (KMP)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3670 Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅, ...

  5. bzoj千题计划250:bzoj3670: [Noi2014]动物园

    http://www.lydsy.com/JudgeOnline/problem.php?id=3670 法一:KMP+st表 抽离nxt数组,构成一棵树 若nxt[i]=j,则i作为j的子节点 那么 ...

  6. BZOJ3670 [Noi2014]动物园

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  7. BZOJ 3670: [Noi2014]动物园 [KMP]

    求这玩意: 对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i] 对1,000,000,007取模的结果 n≤5,L≤1,00 ...

  8. [NOI2014]动物园(kmp)

    题目 https://www.luogu.org/problemnew/show/P2375 做法 查找多少个前缀与后缀配对,其实就是\(fail\)树的深度 而不可重叠,其实\(i\)不可用的,\( ...

  9. BZOJ 3670 NOI2014 动物园 KMP+dp

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3670 题意概述:令num[i]表示字符串由1~i的字符形成的前缀中不相重叠的相同前后缀的数 ...

  10. P2375 [NOI2014]动物园 KMP

    好,暴力能拿$50pts\space qwq$ 暴力的思路就是一直跳$nxt[j]$,直到它的长度小于串的一半,然后开始计数,当然要接着跳$nxt[j]$ 正解:考虑没有长度要求的(不要求不重合)公共 ...

随机推荐

  1. EF(EF Core)中的NotMappedAttribute(转载)

    NotMapped特性可以应用到EF实体类的属性中,Code-First默认的约定,是为所有带有get,和set属性选择器的属性创建数据列..NotManpped特性打破了这个约定,你可以使用NotM ...

  2. 详细解读大数据分析引擎Pig&PigLatin语句

    Pig 一.Pig的介绍: Pig由Yahoo开发,主要应用于数据分析,Twitter公司大量使用Pig处理海量数据,Pig之所以是数据分析引擎,是因为Pig相当于一个翻译器,将PigLatin语句翻 ...

  3. ss客户端的使用

    这里假设读者已经搭建了ss服务.教程 客户端安装 客户端可以通过GitHub上搜索,这里就不写太详细了,避免文章被禁掉. 比如对于mac的用户,可以选择这个 客户端配置 点击程序图标以展开菜单栏 服务 ...

  4. WPF EventTrigger,BeginStoryboard

    <Window x:Class="WpfApplication2.LoginWind" xmlns="http://schemas.microsoft.com/wi ...

  5. c# 淘宝运单查询

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.W ...

  6. 【WPF】如何使用wpf实现屏幕最前端的绘图?

    原文:[WPF]如何使用wpf实现屏幕最前端的绘图? 引言 在知乎上面看到如何使用wpf实现屏幕最前端的绘图? 这么一个问题,觉得全屏弹幕很有趣,所以把它实现了. 实现 界面设置很简单,Window界 ...

  7. JavaEE笔记(十一)

    Spring beans使用参数占位符(JDBC配置读取示例) beans.xml配置文件 <?xml version="1.0" encoding="UTF-8& ...

  8. LoRa---她的简介和她的专业术语

    LoRa是LPWAN(低功耗广域网)通信技术的一种,其作用距离超过 15 公里,连接节点可达 100 万个.低功耗与长距离极限的组合可将最大数据速率提升至每秒 50千比特(Kbps). LoRa 是  ...

  9. Partition3:分区切换(Switch)

    在SQL Server中,对超级大表做数据归档,使用select和delete命令是十分耗费CPU时间和Disk空间的,SQL Server必须记录相应数量的事务日志,而使用switch操作归档分区表 ...

  10. MVC5.0知识点梳理

    我们在使用MVC的时候或许总是在使用着自己一直熟悉的知识点去实现已有的功能,多梳理一些知识点让每种功能的实现方式可以多样化. 我们在开发小型系统时总是使用微软MVC的脚手架功能,比如路由可能就是使用了 ...