理解

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. lmbench andlmbench 移植测试

    /*********************************************************************** * lmbench andlmbench 移植测试 * ...

  2. Atom vim mode

    /******************************************************************** * Atom vim mode * 说明: * 想找一个具有 ...

  3. Junit常用操作

    断言方法: public static void assertEquals(Object[] expected, Object[] actual) // 测试a是否等于b public static ...

  4. bzoj1044 [HAOI2008]木棍分割——前缀和优化DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1044 咳咳...终于A了... 居然没注意到正着找pos是n方会TLE...所以要倒着找po ...

  5. vs2010 每行代码显示虚线

    快捷键:Ctrl+R,W或Ctrl+E,S,即可去除 或者是编辑菜单——高级——查看空白 VS12010代码编辑器横向滚动条 工具----选项-----文本编辑器---所有语言---右侧 自动换行去掉

  6. Ubuntu 12.04 root默认密码? 如何使用root登录? (转载)

    转自:http://www.lupaworld.com/article-219280-1.html 在安装Ubuntu 12.04时并没有设置root的密码,登录的时候也没有使用root账户.当我们使 ...

  7. Mac下Ruby升级与Rails的安装

    也是醉了,网上查了半天一脸懵逼.然后自己动手试试 gem install rails瞬间命令行就没反应了,以为命令行挂了,但是一会儿报错说是没有权限. 好吧,那么来这个 sudo gem instal ...

  8. 三种实现AJAX的方法以及Vue和axios结合使用的坑

    前言 之前曾经想自己写一个天气的App,并找到了一个免费的天气数据接口的服务商--和风天气,当时也不懂怎么发HTTP请求,而且也只会用Java语言,看到官方文档里面有一个Java代码示例,就复制了一下 ...

  9. 安装privoxy后curl 操作

    如果讲privoxy服务关掉 sudo /etc/init.d/privoxy restart 这时候发现 curl www.baidu.com 也没法正常工作,直接显示的是无法连接到相应端口还是 主 ...

  10. 【css】如何实现环形进度条

    最近团队的童鞋接到了一个有关环形进度条的需求,想要还原一个native的沿环轨迹渐变进度条的效果,看到这个效果的时候,笔者陷入了沉思.. 环形进度条的效果,最先想到的就是使用CSS利用两个半圆的hac ...