bzoj 3670: [Noi2014]动物园
Description
近日,园长发现动物园中好吃懒做的动物越来越多了。例如企鹅,只会卖萌向游客要吃的。为了整治动物园的不良风气,让动物们凭自己的真才实学向游客要吃的,园长决定开设算法班,让动物们学习算法。
某天,园长给动物们讲解KMP算法。
园长:“对于一个字符串S,它的长度为L。我们可以在O(L)的时间内,求出一个名为next的数组。有谁预习了next数组的含义吗?”
熊猫:“对于字符串S的前i个字符构成的子串,既是它的后缀又是它的前缀的字符串中(它本身除外),最长的长度记作next[i]。”
园长:“非常好!那你能举个例子吗?”
熊猫:“例S为abcababc,则next[5]=2。因为S的前5个字符为abcab,ab既是它的后缀又是它的前缀,并且找不到一个更长的字符串满足这个性质。同理,还可得出next[1] = next[2] = next[3] = 0,next[4] = next[6] = 1,next[7] = 2,next[8] = 3。”
园长表扬了认真预习的熊猫同学。随后,他详细讲解了如何在O(L)的时间内求出next数组。
下课前,园长提出了一个问题:“KMP算法只能求出next数组。我现在希望求出一个更强大num数组一一对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i]。例如S为aaaaa,则num[4] = 2。这是因为S的前4个字符为aaaa,其中a和aa都满足性质‘既是后缀又是前缀’,同时保证这个后缀与这个前缀不重叠。而aaa虽然满足性质‘既是后缀又是前缀’,但遗憾的是这个后缀与这个前缀重叠了,所以不能计算在内。同理,num[1] = 0,num[2] = num[3] = 1,num[5] = 2。”
最后,园长给出了奖励条件,第一个做对的同学奖励巧克力一盒。听了这句话,睡了一节课的企鹅立刻就醒过来了!但企鹅并不会做这道题,于是向参观动物园的你寻求帮助。你能否帮助企鹅写一个程序求出num数组呢?
特别地,为了避免大量的输出,你不需要输出num[i]分别是多少,你只需要输出对1,000,000,007取模的结果即可。
Input
第1行仅包含一个正整数n ,表示测试数据的组数。随后n行,每行描述一组测试数据。每组测试数据仅含有一个字符串S,S的定义详见题目描述。数据保证S 中仅含小写字母。输入文件中不会包含多余的空行,行末不会存在多余的空格。
Output
包含 n 行,每行描述一组测试数据的答案,答案的顺序应与输入数据的顺序保持一致。对于每组测试数据,仅需要输出一个整数,表示这组测试数据的答案对 1,000,000,007 取模的结果。输出文件中不应包含多余的空行。
Sample Input
aaaaa
ab
abcababc
Sample Output
1
32
HINT
n≤5,L≤1,000,000
Source
这个题打了好久,原来是预处理倍增T粉了;
首先这题肯定是跟KMP有关的,利用nxt数组的性质。
因为前缀和后缀不能相交,所以我们需要暴跳nxt直到2*j<=i为止,才算符合不重叠;
然后如果要求num数组,是还要再暴跳到0的,然后统计跳了几次,但是这个东西可以在求nxt的时候顺便求出来,所以暴跳到一个就可以直接得出答案了。
然后我并不知道复杂度。。。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define RG register
using namespace std;
const int N=1000050;
const int Mod=1000000007;
int nxt[N],cnt[N],len,T,f[N][18],num[N];
long long ans;
char s[N];
void make_nxt() {
cnt[1]=1;int j=0;
for(RG int i=2;i<=len;i++){
while(j&&s[j+1]!=s[i]) j=nxt[j];
if(s[j+1]==s[i]) j++;
nxt[i]=j;cnt[i]=cnt[j]+1;
}
}
void work(){
int j=0;ans=1;
for(RG int i=2;i<=len;i++){
while(j&&s[j+1]!=s[i]) j=nxt[j];
if(s[j+1]==s[i]) j++;
while(2*j>i) j=nxt[j];
ans*=(cnt[j]+1);if(ans>Mod)ans%=Mod;
}
}
int main() {
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
scanf("%d",&T);
while(T--) {
scanf("%s",s+1),len=strlen(s+1);
memset(nxt,0,sizeof(nxt));
memset(num,0,sizeof(num));
memset(cnt,0,sizeof(cnt));
make_nxt();work();printf("%lld\n",ans);
}
}
bzoj 3670: [Noi2014]动物园的更多相关文章
- 字符串(KMP):BZOJ 3670 [Noi2014]动物园
3670: [Noi2014]动物园 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1521 Solved: 813[Submit][Status] ...
- BZOJ 3670: [Noi2014]动物园【KMP变形 】
3670: [Noi2014]动物园 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2738 Solved: 1475[Submit][Status ...
- BZOJ 3670 NOI2014 动物园 KMP+dp
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3670 题意概述:令num[i]表示字符串由1~i的字符形成的前缀中不相重叠的相同前后缀的数 ...
- BZOJ 3670: [Noi2014]动物园 [KMP]
求这玩意: 对于字符串S的前i个字符构成的子串,既是它的后缀同时又是它的前缀,并且该后缀与该前缀不重叠,将这种字符串的数量记作num[i] 对1,000,000,007取模的结果 n≤5,L≤1,00 ...
- 【BZOJ】3670: [Noi2014]动物园
http://www.lydsy.com/JudgeOnline/problem.php?id=3670 题意:太水了= = #include <bits/stdc++.h> using ...
- 【BZOJ】3670: [Noi2014]动物园(KMP)
题目 传送门:QWQ 分析 像求next一样求num. 第二次求next时加上不超过一半的条件. 时间复杂度: $ \huge O ( n ) $ 代码 // luogu-judger-enable- ...
- 3670: [Noi2014]动物园
题目链接 题意:给n个字符串,求出每个字符串的num值,加1后相乘.num[i]表示1~i中,有多少没有重叠的公共前缀后缀. 分析: kmp中p数组表示最大的公共前缀后缀.设一cnt数组,表示1~i中 ...
- bzoj千题计划250:bzoj3670: [Noi2014]动物园
http://www.lydsy.com/JudgeOnline/problem.php?id=3670 法一:KMP+st表 抽离nxt数组,构成一棵树 若nxt[i]=j,则i作为j的子节点 那么 ...
- NOI2014 动物园
3670: [Noi2014]动物园 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 174 Solved: 92[Submit][Status] D ...
随机推荐
- JAVA基础1——字节&位运算
占用字节数 & 取值范围 Java一共有8种基本数据类型(原始数据类型): 类型 存储要求 范围(包含) 默认值 包装类 int 4字节(32位) -2^31~ 2^31-1 0 Intege ...
- js脚本根据身份证号获取性别、年龄、家庭地址、生日
做项目测试时需要根据身份证号获取其信息,也不想调接口,就自己在本地通过收集资料整合了一个
- 十大经典排序算法的JS版
前言 个人博客:Damonare的个人博客 如遇到问题或有更好的优化方法,可以: 提issue给我 或是pull requests 我都会看到并处理,欢迎Star. 这世界上总存在着那么一些看似相似但 ...
- Retrofit网络请求库应用02——json解析
PS:上一篇写了Retrofit网络请求库的简单使用,仅仅是获取百度的源码,来证明连接成功,这篇讲解如何解析JSON数据,该框架不再是我们之前自己写的那样用JsonArray等来解析,这些东西,我们都 ...
- post 与get 区别
刷新/后退按钮 GET后退按钮/刷新无害,POST数据会被重新提交(浏览器应该告知用户数据会被重新提交). 书签 GET书签可收藏,POST为书签不可收藏. 缓存 GET能被缓存 缓存是针对URL来进 ...
- keepalived结合nginx实现nginx高可用
1.简介 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以利用其来避免单点故障.一个LVS服务会有2台服务器运行Keepalived,一台为主服务器(MASTER),一台 ...
- linux进程管理和系统状态查看命令简介
1 进程管理简介 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础 2 常用命令 2.1 pstree 2.1.1 功能描 ...
- HDU 1715 大菲波数
/* 中文题意: 中文翻译: 题目大意:求1000以内的菲波数. 解题思路:用大数来计算.用二维数组来存数. 难点具体解释:用二维数组存数,開始的一维存的是1000个Pi,后面那一维是用来存数字的. ...
- vue路由
vue-router 现在的应用都流行SPA应用(single page application) 传统的项目大多使用多页面结构,需要切换内容的时候我们往往会进行单个html文件的跳转,这个时候受网络 ...
- 基于python的web应用开发-添加关注者
社交web允许用户之间相互联系. 例如: 关注者.好友.联系人.联络人或伙伴. 记录两个用户之间的定向联系,在数据库查询中也要使用这种联系. 一.论数据库关系 一对多关系 数据库使用关系建立记录之间的 ...