20190724 KMP
通了个宵,还得去洗衣服,睡醒做题还时很舒服的,发现可能更适合一个人窝在寝室。
大佬请绕,菜鸡刺猬场
循环节......len - next[len],没有系统学过KMP的小白只能总结成,
next记录相同前缀的尽可能后面的下标,所以next [ i ] 同时记录了是从 1 开始计算的 第几个元素前缀相同,
也说明了前缀的数量。然后公式就很本能了。 从next [ len ] 指代的长度来源为len或者就是next [ len ] 的角
度来看,len - next[len] 既可以后面的周期,也可以代表前面的周期。abcabcabcab,-1// 0 0 0 1 2 3 4 5 6 7 8
11 - 8 = 3 可以是最后两个b之间的周期,也可以说是最后一个b的8个前缀之前的长度,从getnext的角度来看的
话,只有存在某个周期,然后T之后的next才会不断增加,并且增加的速度和下标增加的速度一致。
HDU3746
题意 给你字符串,然后问在最后加上多少字符,可以使得整个字符串是循环的
在最后判别加多少个的时候好像有多种判别方式这里提供两种
#include <stdio.h> #include <string.h> const int maxn = 100000 +10; char s[maxn]; int next[maxn]; int len, length; void getnext() { int i=0, j = -1; next[0] = -1; while (i < len) { while (j != -1 && s[i] != s[j]) j = next[j]; next[++i] = ++j; } } int main() { int t; scanf("%d", &t); while (t--){ scanf("%s", s); len = strlen(s); getnext(); length = len - next[len]; // printf("length = %d = %d - %d\n", length, len, next[len]); if (len % length == 0 && len != length) { puts("0"); }else { //1 printf("%d\n", (length - len % length) == 0 ? (len) : (length - len % length)); //2 printf("%d\n", length - next[len] % length);//next可以确定最后一个元素在上一个周期里 //面的哪个位置,然后去掉前面的周期 } } return 0; }
HDU 2594 Simpsons’ Hidden Talents
题意 输出尽可能长的 s1前缀与s2后缀相同的部分以及长度
思路是第一个拿来当pattern,然后对后面的一个一个匹配,如果前一个满了,就退一次这样最后的结果是前面的尽量跟后面的后面匹配
注意getnext从-1开始,匹配从0开始
int solve() { int len1 = strlen(s1); int len2 = strlen(s2); int i = 0, j = 0; while (i < len2) { if (j == -1 || s1[j] == s2[i]) { i++; j++; if (j == len1 && i != len2) { j = next[j]; } } else j = next[j]; } return j; }
HDU 3366 Count the string
题意 一个串 getnext过程中各个前缀遍历的总次数
想直接统计来着 dp 永远是别人的,我什么也没有
按照搜索的想法是要一个一个getnext下去直到 j == -1,然而,深搜不也经常dp吗?设置dp[ j ] = 从第一个字符(起点) 到 j (点) 的路径长度
#include <stdio.h> #include <string.h> const int maxn = 200000 + 10; const int mod = 10007; char s[maxn]; int next[maxn]; int dp[maxn]; int len, length; void getnext() { int i=0, j = -1; next[0] = -1; int len = strlen(s); while (i < len) { while (j != -1 && s[i] != s[j]) j = next[j]; next[++i] = ++j; } } int main() { int ans; int t; scanf("%d", &t); while (t--) { scanf("%d%s", &len, s); for (int i = 0; i <= len; i++)dp[i] = 0; getnext(); ans = 0; for (int i = 1; i <= len; i++) { dp[i] = dp[next[i]] + 1; dp[i] = dp[i] % mod; ans = ans + dp[i]; ans = ans % mod; } printf("%d\n", ans); } return 0; }