• 【洛谷3426】[POI2005] SZA-Template(KMP)


    点此看题面

    • 有一个长度为(n)的文本串,求一个最小长度的模式串可以打印出这个文本串。
    • 打印是指文本串一个位置可以匹配多次,但每个位置至少要匹配一次。
    • (nle5 imes10^5)

    (KMP)+(DP)

    考虑到这个模式串必然是文本串的一个前缀,因此知道长度就可以推断出其内容。

    所以记录(f_i)表示打印出文本串前(i)个字符所需的最小长度模式串。

    实际上,这个模式串同时也必然是文本串的一个后缀,因此我们(KMP)求出(nxt)数组,那么(f_i)实际上只有两种可能的取值:(i)或者(f_{nxt[i]})

    显然(i>f_{nxt[i]}),因此我们只需验证(f_{nxt[i]})是否可行,那就是要判断是否存在(jin[i-f_{nxt[i]},i))满足(f_j=f_{nxt[i]}),这样一来就可以在(j)的基础上再匹配上一个(f_{nxt[i]})得到(i)

    由于我们是从左往右(DP)的,肯定满足(j<i),因此这等价于判断最大的满足(f_j=f_{nxt[i]})(j)是否大于等于(i-f_{nxt[i]})

    只需开个(g_x)维护一下满足(f_i=x)的最后出现的(i)即可。

    代码:(O(n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 500000
    using namespace std;
    int n,nxt[N+5],f[N+5],g[N+5];char s[N+5];
    int main()
    {
    	RI i,j,x;scanf("%s",s+1),n=strlen(s+1);
    	for(i=2,j=0;i<=n;s[j+1]==s[i]&&++j,nxt[i++]=j) W(j&&s[j+1]^s[i]) j=nxt[j];//KMP求nxt数组
    	for(i=1;i<=n;++i) x=f[nxt[i]],g[f[i]=g[x]>=i-x?x:i]=i;return printf("%d
    ",f[n]),0;//简单DP,只需检验f[nxt[i]]
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Beta 冲刺(7/7)
    Beta 冲刺(6/7)
    Beta 冲刺(5/7)
    Beta 冲刺(4/7)
    Beta 冲刺(3/7)
    Beta 冲刺(2/7)
    Beta 冲刺(1/7)
    福大软工 · 第十次作业
    Adobe acrobat DC 2020 激活方法
    物理八年级下册2
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu3426.html
Copyright © 2020-2023  润新知