首先求出 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_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 gnxti≥i−nxti,则 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;
}