P3426 [POI2005] SZA-Template 题解

题意:

给定一个字符串,求能盖出这个字符串的印章的最小长度。

分析:

显然,这个印章一定是 s 的 border。

dpi 表示盖满前 i 个的最小印章大小,那么答案只可能为 i,或者 dpkmpi

证明如下:

  • 显然答案为 i 是整个字符串。
  • 由于 s 的 border 可以拆分成两部分,即 t 的 border 与 t 本身,dpkmpi 均有。

现在只剩一个问题,什么时候 dpi=dpkmpi 成立呢?

对于两个相交的串 A,B,如果它们均能被 t 盖出,那么 AB 一定能被 t 盖出。因为印章只可能为 AB,因此一定能盖出AB

由于 dpkmpi 能盖出 [1...kmpi],那么它也一定能盖出 [ikmpi+1,i],于是如果 dpkmpi 最远能盖到 ikmpi 及以后,那么就一定能盖完 [1...i]

于是我们再记 hi 表示前缀 i 作为印章时最远能盖到的位置,然后直接转移即可。

代码:

#include<bits/stdc++.h>
#define int long long
#define N 500005
using namespace std;
int n;
int kmp[N], dp[N], h[N];
string s;
signed main() {
    cin >> s;
	n = s.length();
	s = " " + s;
    int j = 0;
	for(int i = 2; i <= n; i++) {
		while(j && (s[j + 1] != s[i])) j = kmp[j];
		if(s[j + 1] == s[i]) j++;
		kmp[i] = j;
	}
	for(int i = 1; i <= n; i++) {
		dp[i] = i;
		if(h[dp[kmp[i]]] >= i - kmp[i]) dp[i] = dp[kmp[i]];
		h[dp[i]] = i;
	}
    cout << dp[n];
	return 0;
}
posted @   小超手123  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示