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

KMP

  • 重点:失配 n x t nxt nxt数组
    • 意义: n x t [ i ] nxt[i] nxt[i]表示在 [ 0 , i − 1 ] [0,i-1] [0,i1]内最长相同前后缀的长度
    • 图示:KMP + BZOJ 4974 [Lydsy1708月赛]字符串大师_第1张图片
      • 此时 n x t [ i ] = j nxt[i]=j nxt[i]=j,即指向最长相同前后缀的后一位置,数值上是最长相同钱后缀的长度
    • 求法:假设我们已知 n x t [ i − 1 ] nxt[i-1] nxt[i1],想要求 n x t [ i ] nxt[i] nxt[i]
      • s t r ( n x t [ i − 1 ] ) = s t r ( i − 1 ) str(nxt[i-1])=str(i-1) str(nxt[i1])=str(i1),显然有 n x t [ i ] = n x t [ i − 1 ] + 1 nxt[i]=nxt[i-1]+1 nxt[i]=nxt[i1]+1
      • s t r ( n x t [ i − 1 ] ) ≠ s t r ( i − 1 ) str(nxt[i-1])\neq str(i-1) str(nxt[i1])̸=str(i1),那么就要往更前面找。因为已知 n x t [ i − 1 ] nxt[i-1] nxt[i1],所以必定出现如下①、②的两段是 [ 0... i − 2 ] [0...i-2] [0...i2]的最长相同前后缀。 j j j n x t [ n x t [ i − 1 ] ] nxt[nxt[i-1]] nxt[nxt[i1]],所以只要 j j j i − 1 i-1 i1配对即可。如果不行,那就如此反复下去,一直到头。其实也可以把这个过程看作自己和自己匹配KMP + BZOJ 4974 [Lydsy1708月赛]字符串大师_第2张图片

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

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

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

AC code

#include 
#include 
#include 
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]);
}

你可能感兴趣的:(KMP,bzoj)