首页 > 其他分享 >CF1286E

CF1286E

时间:2022-11-09 12:11:15浏览次数:49  
标签:nxt 26 val lst fail CF1286E border

显然只需要考虑每次加入一个新点的答案。
把加点之后不再是 border 的 border 删掉,把仍然是border的用 \(w[i]\) 更新一下答案(取个min)。
每次最多加入一个border,每个border最多会被删除一次。所以是\(O(n)\)的。
而每次用map暴力更新答案的话,均摊\(O(log_n)\)


以上内容默认看过题解。
时间复杂度瓶颈在于如何找到不合法的。
多数题解都说:“用kmp的失配指针构建一棵树” 或 “画出kmp的fail树”。看不懂。

附一张fail树的配图:
image
我们定义一个位置 \(i\) 的颜色为 \(s[nxt[i] + 1]\)
首先插入 \(i\) 之前的 border 都是针对 \(i-1\) 合法的 border,所以都是在 \(i-1\) 的 fail 树上的。
考虑暴力 : 从 \(i-1\)开始暴力跳nxt,看 fail 树上每个位置是否合法(颜色是否等于\(s[i]\))。
优化一下,一共有\(26\)种颜色(\(26\)个字母),而我们只留下一种(\(s[i]\)),维护一个数组\(lst[i][j]\),表示在 \(i\) 所处的 fail 树上,在 \(i\) 之前第一个颜色为 \(j\) 的位置,然后.......就硬跳。

点击查看代码
	for(int j = 0 ; j < 26 ; j++)lst[i][j] = lst[nxt[i]][j];
        lst[i][s[nxt[i]+1]-'a'] = nxt[i];

        for(int j = 0 ; j < 26 ; j++)
        {
            if(j + 'a' == s[i])continue;
            for(ll k = lst[i-1][j] ; k ; k = lst[k][j])
            {
                ll val = query(1,1,n,i-k,i-1);
                mp[val]--;
                ans -= val;
            }
        }

标签:nxt,26,val,lst,fail,CF1286E,border
From: https://www.cnblogs.com/lei35/p/16873193.html

相关文章

  • CF1286E
    考虑在每次加入一个字符后,求出所有合法后缀(即border)的权值和。容易想到用KMP算法解决。具体的,我们维护border的集合。加入一个字符\(c_i\)后,对集合的改变为:如果......