理解

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. I.MX6 逻辑分析仪 UART

    /*********************************************************************** * I.MX6 逻辑分析仪 UART * 说明: * ...

  2. python名片管理系统

    1.代码: (1)主程序 #!/usr/bin/env python # -*- coding: UTF-8 -*- import cards_tools # 无限循环,由用户主动决定什么时候退出循环 ...

  3. 字符设备驱动另一种写法—mmap方法操作LED

    最近在看韦老师的视频,讲解了很多种字符设备的驱动写法.经过自己的研究之后,我发现还有另外一种写法,直接在应用层操作,省去了内核中的地址映射部分,使得用户可以在应用层直接操作LED.        mm ...

  4. bzoj4390

    树上差分 感觉挺巧妙的... 每次更新就是在u,v上+1,x是lca(u,v),在x和fa[x]上-1,那么每个点的权值就是子树和,正确性yy一下就行了 不过树状数组的常数真是小,改成前缀和才快了20 ...

  5. 淘淘商城项目_同步索引库问题分析 + ActiveMQ介绍/安装/使用 + ActiveMQ整合spring + 使用ActiveMQ实现添加商品后同步索引库_匠心笔记

    文章目录 1.同步索引库问题分析 2.ActiveM的介绍 2.1.什么是ActiveMQ 2.2.ActiveMQ的消息形式 3.ActiveMQ的安装 3.1.安装环境 3.2.安装步骤 4.Ac ...

  6. linux更改用户名,域名(转载)

    转自:http://huangro.iteye.com/blog/365975 1. 我们在root权限下,使用命令: usermod -l new_user_name old_user_name 即 ...

  7. bzoj 4817: [Sdoi2017]树点涂色【树链剖分+LCT】

    非常妙的一道题. 首先对于操作一"把点x到根节点的路径上所有的点染上一种没有用过的新颜色",长得是不是有点像LCT中的access操作?进而发现,如果把同一颜色的点连起来作为LCT ...

  8. UVA - 10859 Placing Lampposts 放置街灯

    Placing Lampposts 传送门:https://vjudge.net/problem/UVA-10859 题目大意:给你一片森林,要求你在一些节点上放上灯,一个点放灯能照亮与之相连的所有的 ...

  9. Tree POJ - 174

    点分模板题 都快改的跟题解一模一样了2333333 #include<cstdio> #include<cstring> #include<algorithm> u ...

  10. 题解报告:hdu 1284 钱币兑换问题(简单数学orDP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1284 Problem Description 在一个国家仅有1分,2分,3分硬币,将钱N兑换成硬币有很 ...