MENU

Solution. LG3426 [POI2005]SZA-Template

Description 展开目录

用一个印章印出字符串 S,印章每次会将所有字符印到纸上,印上去的字母无法被覆盖,求最小的印章长度。

|S|5×105

Solution 展开目录

若印章能印出 S,则必然能印出 S 的最长 border,即 nxti,这启发我们 dp。

fi 表示能引出 S0i 的最小印章长度,则 fi=i or fnxti

考虑什么时候能够通过 nxti 转移,这一点题解里普遍很简略。

已知,S0i 的 border 部分能够通过印章印出,我们希望知道当前印章能否印出中间的部分,于是我们查找是否存在 fj 使得 fj=fnxti,jinxti,前者保证了 fjfnxti 对应了同一个印章,后者保证了 fj 覆盖了我们未知的部分。

具体实现时我们维护每个 dp 值对应的最大下标即可。

Code 展开目录

  • namespace Main{
  • const int N = 500005;
  • int n, nxt[N], f[N], cnt[N];
  • char s[N];
  • void Main(){
  • scanf("%s", s + 1);
  • n = strlen(s + 1);
  • for(int i = 2, j = 0; i <= n; i++){
  • while(j && 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++){
  • f[i] = i;
  • if(cnt[f[nxt[i]]] >= i - nxt[i]) f[i] = f[nxt[i]];
  • cnt[f[i]] = i;
  • }
  • write(f[n]);
  • return;
  • }
  • }
Last Modified: October 23, 2022
Archives Tip
QR Code for this page
Tipping QR Code