• KMP + BZOJ 4974 [Lydsy1708月赛]字符串大师


    KMP

    • 重点:失配nxtnxt数组
      • 意义:nxt[i]nxt[i]表示在[0,i1][0,i-1]内最长相同前后缀的长度
      • 图示:在这里插入图片描述
        • 此时nxt[i]=jnxt[i]=j,即指向最长相同前后缀的后一位置,数值上是最长相同钱后缀的长度
      • 求法:假设我们已知nxt[i1]nxt[i-1],想要求nxt[i]nxt[i]
        • str(nxt[i1])=str(i1)str(nxt[i-1])=str(i-1),显然有nxt[i]=nxt[i1]+1nxt[i]=nxt[i-1]+1
        • str(nxt[i1])str(i1)str(nxt[i-1]) eq str(i-1),那么就要往更前面找。因为已知nxt[i1]nxt[i-1],所以必定出现如下①、②的两段是[0...i2][0...i-2]的最长相同前后缀。jjnxt[nxt[i1]]nxt[nxt[i-1]],所以只要jji1i-1配对即可。如果不行,那就如此反复下去,一直到头。其实也可以把这个过程看作自己和自己匹配在这里插入图片描述

    一道题目:BZOJ 4974[Lydsy1708月赛]字符串大师

    题目链接:BZOJ 4974[Lydsy1708月赛]字符串大师

    • 稍微做判断可得到,给出的perper数组满足性质:pre[i]=inxt[i]pre[i]=i-nxt[i]
    • 于是求出nxtnxt数组后考虑怎么构造,只要满足位置ii的值等于nxt[i+1]nxt[i+1]的值就行了。如果nxt[i+1]nxt[i+1]等于0,就在沿nxt移动过程中,打一下标记,最后取最小字典序就行了

    AC code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int MAXN = 100005;
    int n, nxt[MAXN], str[MAXN];
    bool vis[MAXN][26];
    
    int main()
    {
        scanf("%d", &n);
        for(int i = 1, x; i <= n; ++i)
            scanf("%d", &x), nxt[i] = i-x;
        nxt[0] = -1;
        for(int i = 0; i < n; ++i)
        {
        	int j = nxt[i], k;
            while(nxt[i+1] != j+1)
                vis[i][str[j]] = 1, j = nxt[j];
            if(~j) str[i] = str[j];
            else
            {
                for(k = 0; k < 26; ++k)
                    if(!vis[i][k]) break;
                str[i] = k;
            }
        }
        for(int i = 0; i < n; ++i) putchar('a'+str[i]);
    }
    
  • 相关阅读:
    贪心法之最优装载问题
    判断回文
    P1217 [USACO1.5]回文质数 Prime Palindromes
    李白打酒
    P1036 选数
    P1028 数的计算
    P1316 丢瓶盖
    P1181 数列分段Section I
    P1182 数列分段`Section II`
    P1216 [IOI1994][USACO1.5]数字三角形 Number Triangles
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039441.html
Copyright © 2020-2023  润新知