• 题解 [LuoguP3426][POI2005]SZA-Template


    Luogu Link

    题解 P3426(kmp)

    首先求出 next \text{next} next 数组(记为 n x t i nxt_i nxti)。

    f i f_i fi 表示印制 [ 1 , i ] [1,i] [1,i] 所需最小印章, g i g_i gi 表示 [ 1 , i ] [1,i] [1,i] 的印章最长能印多长。

    可以发现 f i f_i fi 只会有两种值: i , f n x t i i,f_{nxt_i} i,fnxti。证明如下。

    • 如果 f i < f n x t i f_i<f_{nxt_i} fi<fnxti,但 [ 1 , f i ] [1,f_i] [1,fi] 必然能印制完 [ 1 , n x t i ] [1,nxt_i] [1,nxti],则 f i ≥ f n x t i f_i \geq f_{nxt_i} fifnxti 矛盾。
    • 如果 f i > f n x t i f_i > f_{nxt_i} fi>fnxti f i ≠ i f_i \neq i fi=i,因为在同一位置上印不同字符是不允许的,所以必然 [ 1 , f i ] [1,f_i] [1,fi] [ 1 , i ] [1,i] [1,i] 的后缀,也是前缀,所以可以用 f i f_i fi 更新 n x t i nxt_i nxti 的值,矛盾。
    • 如果 f i > i f_i > i fi>i,显然不成立。

    接下来考虑什么时候 f i f_i fi 能取到 f n x t i f_{nxt_i} fnxti:考虑 g n x t i g_{nxt_i} gnxti,若 g n x t i ≥ i − n x t i g_{nxt_i}\geq i-nxt_i gnxtiinxti,则 f i f_i fi 能取到 f n x t i f_{nxt_i} fnxti。在计算完 f i f_i fi 的时候更新 g f i g_{f_i} gfi i i i 即可。

    //P3426
    #include <cstring>
    #include <cstdio>
    
    const int N = 5e5 + 10;
    int n, nxt[N], f[N], g[N];
    char s[N];
    
    int main(){
    	scanf("%s", s+1);
    	n = strlen(s+1);
    	for(int i = 2, j = 0; i <= n; ++ i){
    		while(j > 0 && s[i] != s[j+1]) j = nxt[j];
    		if(s[i] == s[j+1]) ++ j;
    		nxt[i] = j;
    	}
    	for(int i = 1; i <= n; ++ i){
    		if(g[f[nxt[i]]] >= i-nxt[i]) f[i] = f[nxt[i]];
    		else f[i] = i;
    		g[f[i]] = i;
    	}
    	printf("%d\n", f[n]);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
  • 相关阅读:
    SPA项目开发之首页导航+左侧菜单
    卧兔网络开启全球红人分销功能,WotoHub上线Shopify应用商店!
    python.py文件如何生成.exe
    Vue 插槽的理解与基础应用
    C# 委托
    文字与视频结合效果
    OpenHarmony鸿蒙南向开发案例:【智能猫眼(基于3518开发板)】
    基于Simulink的用于电力系统动态分析
    国际结算重点完整版
    Spring AOP以及统一处理
  • 原文地址:https://blog.csdn.net/im_zyINF/article/details/125486823