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 
#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 
#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;
}

 

你可能感兴趣的:(20190724 KMP)