zoukankan      html  css  js  c++  java
  • 似乎在梦中见过的样子 (KMP)

    # 10047. 「一本通 2.2 练习 3」似乎在梦中见过的样子

    【题目描述】

    「Madoka,不要相信 QB!」伴随着 Homura 的失望地喊叫,Madoka 与 QB 签订了契约。

    这是 Modoka 的一个噩梦,也同时是上个轮回中所发生的事。为了使这一次 Madoka 不再与 QB 签订契约,Homura 决定在刚到学校的第一天就解决 QB。然而,QB 也是有许多替身的(但在第八话中的剧情显示它也有可能是无限重生的),不过,意志坚定的 Homura 是不会放弃的——她决定消灭所有可能是 QB 的东西。现在,她已感受到附近的状态,并且把它转化为一个长度为 nnn 的字符串交给了学 OI 的你。

    现在你从她的话中知道,所有形似于 $A+B+A$ 的字串都是 QB 或它的替身,且 $|A|ge k,|B|ge 1$(位置不同其他性质相同的子串算不同子串,位置相同但拆分不同的子串算同一子串),然后你必须尽快告诉 Homura 这个答案——QB 以及它的替身的数量。

    【算法】a

    基本地:由于 $O(n^2)$ 就行,枚举子串左端点,计算每个子串的特征向量,对符合要求的累加。
    特别地:KMP中计算的特征向量 $nxt[i]$ 表示的是以i为右端点,题目中A串的最小长度,由于题目对A的长度做了限制。于是,我们另开一个数组 $f$,记录满足A长度条件的最小长度 j,若 j 同时满足 $2*j<i$ 则累加。
    收获:nxt数组本质上可以看作父节点表示法表示的一颗树,我们自根向下延申。要记录的是中间的满足条件的点。(之前最大循环节那道题 f 数组记录的就是根节点的值,不过我没意识到是棵树。。)

    【代码】

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    int k,n;
    ll ans;
    int nxt[20000],f[20000];
    char s[20000];
    void get_nxt(int x) {
        nxt[1]=0;
        for(int i=2,j=0;i<=n-x;i++) {
            while(j>0&&s[i+x]!=s[j+x+1]) j=nxt[j];
            if(s[j+x+1]==s[i+x]) j++;
            nxt[i]=j;
            if(f[j]) f[i]=f[j];
            else if(j>=k) f[i]=j;
            else f[i]=0;
            if(f[i]&&(f[i]<<1)<i) ans++;
        }
    }
    int main() {
        scanf("%s%d",s+1,&k);
        n=strlen(s+1);
        for(int i=1;i<=n;i++) {
            get_nxt(i-1);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
    
  • 相关阅读:
    JAVA学习日报 7.24
    JAVA学习日报 7.23
    JAVA学习日报 7.22
    【刷题-LeetCode】275. H-Index II
    【刷题-LeeetCode】260. Single Number III
    【刷题-LeetCode】240. Search a 2D Matrix II
    【刷题-LeetCode】239. Sliding Window Maximum
    【刷题-LeetCode】238. Product of Array Except Self
    【经验总结】VSCode中找不到numpy/matplotlib/pillow,navigator没了
    【刷题-LeetCode】236. Lowest Common Ancestor of a Binary Tree
  • 原文地址:https://www.cnblogs.com/Willendless/p/9614641.html
Copyright © 2011-2022 走看看