描述


http://www.lydsy.com/JudgeOnline/problem.php?id=3670

对于一个字符串,求出num数组,其中num[i]表示前i个字符构成的字串中不相重合的相同前后缀共有多少对.

3670: [Noi2014]动物园

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 1740  Solved: 923
[Submit][Status][Discuss]

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

3
aaaaa
ab
abcababc

Sample Output

36
1
32

HINT

n≤5,L≤1,000,000

Source

分析


在做kmp的自匹配时,顺便记录一个cnt数组,其中cnt[i]表示第i个字符需要进行几次i=fail[i]到达0,也就是如果失配时跳转到i位置,包括i位置,之前共有多少可以作为失配时跳转对象的(也就是有多少满足和后面某一后缀相同的前缀).第二遍做子匹配时,将失配指针一直跳到小于等于i/2的位置j,此时cnt[j]就是共有多少满足的相同前缀后缀组即num[i].(手画画更清楚点?)

p.s.第二次匹配时如果i位置跳转到了k,那么k之后的任意数k'都满足k'>i/2,那么在i+1时,k'+1>(i+1)/2,所以如果在i位置跳转到了k,在i+1位置继续从k+1位置即可.

 #include <cstdio>

 const int mod=1e9+;
const int maxn=1e6+;
int ans;
char c[maxn];
int fail[maxn],cnt[maxn]; void kmp(){
int j=;
fail[]=,cnt[]=;
for(int i=;c[i];i++){
while(j&&c[j+]!=c[i]) j=fail[j];
if(c[i]==c[j+]) j++;
fail[i]=j;
cnt[i]=cnt[j]+;
}
j=;ans=;
for(int i=;c[i];i++){
while(j&&c[j+]!=c[i]) j=fail[j];
if(c[i]==c[j+]) j++;
while((j<<)>i) j=fail[j];
ans=((long long)ans*(long long)(cnt[j]+))%mod;
}
} int main()
{
int n;
scanf("%d",&n);
while(n--){
scanf("%s",c+);
kmp();
printf("%d\n",ans);
}
return ;
}

BZOJ_3670_[NOI2014]_动物园_(kmp)的更多相关文章

  1. UOJ #5. 【NOI2014】动物园 扩大KMP

    第一次NOI称号. ... 扩展假设知道KMP如果. .. . 就是水题了. ... #5. [NOI2014]动物园 统计提交情况 描写叙述 提交 近日.园长发现动物园中好吃懒做的动物越来越多了.比 ...

  2. 【BZOJ3670】【NOI2014】动物园(KMP算法)

    [BZOJ3670]动物园(KMP算法) 题面 BZOJ 题解 神TM阅读理解题 看完题目之后 想暴力: 搞个倍增数组来跳\(next\) 每次暴跳\(next\) 复杂度\(O(Tnlogn)\) ...

  3. BZOJ_3670_[Noi2014]动物园_KMP

    BZOJ_3670_[Noi2014]动物园_KMP Description 近日,园长发现动物园中好吃懒做的动物越来越多了.例如企鹅,只会卖萌向游客要吃的.为了整治动物园的不良风气,让动物们凭自己的 ...

  4. uoj #5. 【NOI2014】动物园 kmp

    #5. [NOI2014]动物园 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/5 Description 近日 ...

  5. uoj #5. 【NOI2014】动物园

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

  6. Oracle学习总结_day03_day04_条件查询_排序_函数_子查询

    本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! day03_条件查询_排序_函数 清空回收站: PUR ...

  7. C Primer Plus_第6章_循环_编程练习

    1.题略 #include int main(void) { int i; char ch[26]; for (i = 97; i <= (97+25); i++) { ch[i-97] = i ...

  8. 转:HIBERNATE一些_方法_@注解_代码示例---写的非常好

    HIBERNATE一些_方法_@注解_代码示例操作数据库7步骤 : 1 创建一个SessionFactory对象 2 创建Session对象 3 开启事务Transaction : hibernate ...

  9. 迅为4412开发板Linux驱动教程——总线_设备_驱动注册流程详解

    本文转自:http://www.topeetboard.com 视频下载地址: 驱动注册:http://pan.baidu.com/s/1i34HcDB 设备注册:http://pan.baidu.c ...

随机推荐

  1. ACM/ICPC ZOJ1006-Do the Untwist 解题代码

    #include <iostream> #include <string> #include <stdlib.h> using namespace std; int ...

  2. J2EE、J2SE、J2ME

    http://developer.51cto.com/art/200906/130453.htm 本文介绍Java的三大块:J2EE.J2SE和J2ME.J2SE就是Java2的标准版,主要用于桌面应 ...

  3. DOS 全集

       DOS全集 winver 检查Windows版本 wmimgmt.msc 打开Windows管理体系结构(wmi) wupdmgr Windows更新程序 wscript Windows脚本宿主 ...

  4. AndroidManifest.xml中的android:name是否带.的区别

    如果android:name所指示的类在定义的package="org.crazyit.ui"下,加不加点无所谓:但如果android:name指示的类在在package下的子包中 ...

  5. O-C相关05:方法的封装.

    前言:在 OC 中进行封装, 就是实现设置实例变量和获取实例变量数据的方法, 常常称为 setter 方法和 getter 方法. 或称为 get set 读写器. 1,setter 方法 sette ...

  6. objective-c中的category

    如果有如下一个类 #import <Foundation/Foundation.h> @interface Person : NSObject @property int age; @en ...

  7. C/C++随机数rand()和种子函数srand()

    在计算机编程中,常常要产生一个随机数.但是要让计算机产生一个随机数并不那么容易.计算机的执行,是以代码来进行的,所以并不可能像抽牌,扔骰子那样产生一个真正具有随机意义的数.只可能以一定的算法产生一个伪 ...

  8. java web 文件上传下载

    文件上传下载案例: 首先是此案例工程的目录结构:

  9. bzoj2653:middle

    思路:首先容易想到二分答案,但如何去check呢,对于一段区间[l,r],把所有小于答案的都赋值为-1,大于等于它的都赋值为1,然后求左端点在[a,b],右端点在[c,d]的最大子串和即可(也就是区间 ...

  10. 计算字符串和文件的MD5值

    //计算字符串的MD5值 public string GetMD5(string sDataIn) { MD5CryptoServiceProvider md5 = new MD5CryptoServ ...