(POJ)1961
来源:互联网 发布:比特币挖矿软件下载 编辑:程序博客网 时间:2024/05/16 11:33
Description
Input
number zero on it.
Output
Sample Input
3aaa12aabaabaabaab0
Sample Output
Test case #12 23 3Test case #22 26 29 312 4
Source
Southeastern Europe 2004
题意:告诉你字符串的长度和字符串本身,要求对于每个字符串。输出所有重复前缀子串(连续出现次数>1),最后停留的索引位置,以及最大重复的次数。以“aabaabaabaab”为例子,索引停留在2时,存在“a”重复2次;3、4、5都没有前缀重复;索引停留在6时,存在“aab”重复2次;索引停留在“9”时,存在“aab”重复3次;索引停在12时,存在“aab”重复4次。
分析:这个题目容易让人联想到KMP算法。首先回忆一下next数组存放的是什么(当前位置最大前缀后缀匹配长度),假设next位置为i,那么next[i]表示将模式串向右移动这么多位置,在第i个位置的字母依旧可以匹配他本身。这道题不存在模式串和原始串,都是自身之内的比较。那么假设我们把“aabaabaabaab”的next数组算出来了,假设在位置i并且有连续的前缀情况下(这个是前提)——那么i-next[i]就是这个最大前缀的最小重复长度。当i=9时,next[i]=6(“aabaab”),也就是将这个字符串右移动6个字母位,第9位依旧可以匹配上,i-next[i]=3(“aab”),重复前缀为i/(i-next[i])=3。
还不理解的话,请记住,我们在求next的过程中就保证了存在重复前缀是i%(i-next[i])==0的充要条件。
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std;const int MAXN=1000000+10;char s[MAXN];int nex[MAXN];void preKMP(){ int p=0,q=-1; nex[0]=-1; while(s[p]){ while(q!=-1 && s[q]!=s[p]) q=nex[q]; nex[++p]=++q; }}void KMP(){ preKMP(); for(int i=2;s[i-1];i++){ int t=i-nex[i]; if(i%t==0 && i/t>1) printf("%d %d\n",i,i/t); }}int main(){ int n,cnt=0; while(scanf("%d",&n)&&n){ scanf("%s",s); printf("Test case #%d\n",++cnt); KMP(); printf("\n"); } return 0;}
还有不使用KMP算法的代码:传送门
把这个题进行简化,一个长度为L的串,按照这题要输出在i[1...L]位置时,前缀循环节最大重复次数。
就把一个问题变成了L个子问题,从头开始找循环节(无需循环到末尾)也很好解决。
拥有巧妙的做题思路是多么的重要啊!
#include<iostream> #include<cstring> #include<cstdio> #include<string> #include<algorithm> using namespace std; #define N 1000010 char s[N]; int nextval[N]; int len; void getnext(const char *s) { int i = 0, j = -1; nextval[0] = -1; while(i != len) { if(j == -1 || s[i] == s[j]) nextval[++i] = ++j; else j = nextval[j]; } } int main() { int T = 1; int length, add; while(scanf("%d", &len) && len) { scanf("%s", s); getnext(s); printf("Test case #%d\n", T++); for(int i = 1; i <= len; ++i) { length = i - nextval[i]; //循环节的长度 if(i != length && i % length == 0) //如果有多个循环 printf("%d %d\n", i, i / length); } printf("\n"); } return 0; }
- POJ-1961(KMP)
- POJ 1961 (KMP)
- POJ 1961 (KMP)
- (POJ)1961
- KMP算法的练习题(poj 3461、poj 2752、poj 2406、poj 1961)
- POJ 1961-Period (KMP)
- POJ 1961 Period(KMP)
- POJ - 1961 Period(水)
- poj 1961 Period(kmp)
- POJ 1961 Period(KMP)
- poj 1961 Period(KMP)
- poj 1961 Period(KMP)
- POJ 1961 Period(KMP)
- POJ 1961Period (KMP)
- poj 1961 Period(kmp)
- poj 1961
- POJ 1961
- 【POJ 1961】
- 下滑隐藏上滑显示的Behavior
- java基础——day03
- Unity3D 之 OnTriggerEnter和OnCollisionEnter的区别
- 【SSH网上商城项目实战05】完成数据库的级联查询和分页
- 如何创建一个多线程任务
- (POJ)1961
- 自定义正方形三秒改变颜色
- 3.替换空格
- [LeetCode]448. Find All Numbers Disappeared in an Array(查找数组中消失的所有数字)
- Linux 实用命令
- 大数据Hadoop
- 蓝桥杯-格子刷油漆-动态规划-java
- Java HashMap源码小结
- Python Error1: ValueError: range parameter must be finite.