理解

1、next数组一直往前走

next数组一直往前走,得到的所有前缀也是当前主串的后缀,当然了,也是当前主串的前缀。

2、周期性字符串

1、周期性字符串$\Leftrightarrow n \,\% \, (n-next[n]) == 0 \ \&\& \ next[n] {\ } {\!}!{=} \  0 $,循环节长度是$n-next[n]$。

2、next数组往前跳的步长是一样的,除了最后一次。即$i-next[i]$保持恒定。

应用

思路:先求出next数组,然后遍历一遍next数组得到所有字符结尾的字符串循环节的长度及个数

代码:

 #include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int maxn = + ;
int nexts[maxn],n;
char s[maxn]; void pre_kmp()
{
int i = , j = nexts[] = -;
while (i < n)
{
while (j != - && s[i] != s[j]) j = nexts[j]; //当前不匹配,j回退,寻找是否存在一个长度较小的字串和开头的字串相等
nexts[++i] = ++j; //j等于已匹配的长度,如果当前位置也匹配,则nexts直接为j+1
}
} void slove()
{
pre_kmp();
for(int i = ; i <= n; i++)
if (i % (i - nexts[i]) == && nexts[i] != ) printf("%d %d\n", i, i / (i - nexts[i]));
} int main()
{
int T = ;
while (scanf("%d",&n) == && n)
{
scanf("%s", s);
s[n] = '#';
if (T) printf("\n");
printf("Test case #%d\n", ++T);
slove();
}
return ;
}

思路:先求next数组,再直接求循环节

代码:

 #include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int maxn = + ;
int nexts[maxn],n;
char s[maxn]; void pre_kmp()
{
int i = , j = nexts[] = -;
//int n = strlen(s);
while (i < n)
{
while (j != - && s[i] != s[j]) j = nexts[j]; //当前不匹配,j回退,寻找是否存在一个长度较小的字串和开头的字串相等
nexts[++i] = ++j; //j等于已匹配的长度,如果当前位置也匹配,则nexts直接为j+1
}
} void slove()
{
pre_kmp();
if (n % (n - nexts[n]) != ) printf("1\n");
else printf("%d\n", n / (n - nexts[n]));
} int main()
{
int T = ;
while (scanf("%s", s) == && s[] != '.')
{
n = strlen(s);
s[n] = '#';
slove();
}
return ;
}

思路:求所有前缀出现的次数和,由于next数组回退得到的前缀也是主串的后缀,所以所有next回退的次数加上本身的一次取模就是答案。

代码:

 #include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int mod = ;
const int maxn = + ;
int nexts[maxn], n;
char s[maxn]; void pre_kmp()
{
int i = , j = nexts[] = -;
//int n = strlen(s);
while (i < n)
{
while (j != - && s[i] != s[j]) j = nexts[j]; //当前不匹配,j回退,寻找是否存在一个长度较小的字串和开头的字串相等
nexts[++i] = ++j; //j等于已匹配的长度,如果当前位置也匹配,则nexts直接为j+1
}
} void slove()
{
int ans = n;
pre_kmp();
for (int i = n; i > ; i--)
{
int k = nexts[i];
while (k > )
{
ans = (ans + ) % mod;
k = nexts[k];
}
}
printf("%d\n", ans);
} int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
scanf("%s", s);
slove();
}
return ;
}

思路:题目大意:问至少添加多少个字符,使得这个字符串有至少两个循环节。若本身有两个循环节返回0,否则补充至两个循环节。

代码:

 #include<cstdio>
#include<cstring>
#include<iostream>
using namespace std; const int mod = ;
const int maxn = + ;
int nexts[maxn], n;
char s[maxn]; void pre_kmp()
{
int i = , j = nexts[] = -;
n = strlen(s);
while (i < n)
{
while (j != - && s[i] != s[j]) j = nexts[j]; //当前不匹配,j回退,寻找是否存在一个长度较小的字串和开头的字串相等
nexts[++i] = ++j; //j等于已匹配的长度,如果当前位置也匹配,则nexts直接为j+1
}
} void slove()
{
pre_kmp();
int len = n - nexts[n];
if (n % len == && nexts[n] != ) printf("0\n");
else printf("%d\n", len - nexts[n] % len);
} int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%s", s);
slove();
}
return ;
}

参考链接:

1、https://vjudge.net/contest/278481#overview

2、https://blog.csdn.net/hkh746392783/article/details/52015293

KMP中next数组的理解与应用的更多相关文章

  1. KMP中next数组的理解

    next数组是KMP的核心,但对于next数组我们总是有时候感觉明白了,但有时候又感觉没明白,现在我就说下我自己对KMP中next数组的理解,首先next[i]上的数字的意义,next[i]表示的是当 ...

  2. POJ 2752 KMP中next数组的理解

    感觉这里讲的挺好的.http://cavenkaka.iteye.com/blog/1569062 就是不断递归next数组.长度不断减小. 题意:给你一个串,如果这个串存在一个长度为n的前缀串,和长 ...

  3. POJ 2752 KMP中next数组的应用

    题意: 让你从小到大输出给的字符串中既是前缀又是后缀的子串的长度. 思路: 先要了解这个东西: KMP中next数组表示的含义:记录着字符串匹配过程中失配情况下可以向前多跳几个字符,它描述的也是子串的 ...

  4. KMP算法中next数组的理解与算法的实现(java语言)

    KMP 算法我们有写好的函数帮我们计算 Next 数组的值和 Nextval 数组的值,但是如果是考试,那就只能自己来手算这两个数组了,这里分享一下我的计算方法吧. 计算前缀 Next[i] 的值: ...

  5. poj 2406 Power Strings (kmp 中 next 数组的应用||后缀数组)

    http://poj.org/problem?id=2406 Power Strings Time Limit: 3000MS   Memory Limit: 65536K Total Submiss ...

  6. E - Period(KMP中next数组的运用)

    一个带有 n 个字符的字符串 s ,要求找出 s 的前缀中具有循环结构的字符子串,也就是要输出具有循环结构的前缀的最后一个数下标与其对应最大循环次数.(次数要求至少为2) For each prefi ...

  7. 对于kmp求next数组的理解

    首先附上代码 1 void GetNext(char* p,int next[]) 2 { 3 int pLen = strlen(p); 4 next[0] = -1; 5 int k = -1; ...

  8. HDU 3746 Cyclic Nacklace(求补齐循环节最小长度 KMP中next数组的使用 好题!!!)

    Cyclic Nacklace Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  9. POJ1961(kmp中Next数组的性质)

    对于某个位置i,i - Next[i]是循环节长度,i整除(i - Next[i])时是完整的几个循环元. ; int n, kase, Next[maxn]; char ch[maxn]; inli ...

随机推荐

  1. mysql04--存储过程

    过程:若干语句,调用时执行封装的体.没有返回值的函数. 函数:是一个有返回值的过程 存储过程:把若干条sql封装起来,起个名字(过程),并存储在数据库中. 也有不存储的过程,匿名过程,用完就扔(mys ...

  2. yii2.0 ActiveRecord 查询汇总

    User::find()->all(); 此方法返回所有数据: User::findOne($id); 此方法返回 主键 id=1 的一条数据(举个例子): User::find()->w ...

  3. 四:多线程--NSOperation简单介绍

    一.NSOperation简介 1.NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程 NSOperation和NSOperationQu ...

  4. wpa_supplicant drivers 查看跟踪

    /**************************************************************************** * wpa_supplicant drive ...

  5. bzoj3668 [Noi2014]起床困难综合症——贪心

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3668 一开始想着倒序推回去看看这一位能不能达到来着,因为这样好中途退出(以为不这样会T): ...

  6. 大神是怎样用函数式JavaScript计算数组平均值的

    译者按: 有时候一个算法的直观.简洁.高效是需要作出取舍的. 原文: FUNCTIONAL JAVASCRIPT: FIVE WAYS TO CALCULATE AN AVERAGE WITH ARR ...

  7. ES高级查询

    Query Content 在查询过程中,除了判断文档是否满足查询条件外,ES还会计算一个_score来标识匹配的程度,旨在判断目标文档和查询条件的匹配有多好 # POST 192.168.100.1 ...

  8. ES的简单增删改查

    1.查看全部索引 GET:192.168.100.102:9200/_cat/indices 2.创建名为news的索引 PUT:192.168.100.102:9200/news 3.新增docum ...

  9. centos 6.4 源码安装php5.4 mysql5.5 apahce2

    centos 6.4 源码安装php5.4 mysql5.5 apahce2 博客分类: php   参考:http://blog.csdn.net/simpleiseasy/article/deta ...

  10. Python圈中的符号计算库-Sympy(转载)

    <本文来自公众号“大邓带你玩python”,转载> import math math.sqrt(8) 2.8284271247461903 我们看看Python中结果 math.sqrt( ...