解析
做出来了就是胜利!
个人感觉虽然我这个nxt树的码量会大一点,但是思路其实比较自然。(看题解区也有)
也是一个相当可取的做法。
现在来讲讲巧妙的dp做法。
考虑直接嗯设:fif_ifi 表示覆盖 [1,i][1,i ][1,i] 的最小印章。
一个比较显然的结论是,fif_ifi 要么是一个border,要么是前缀 i 本身。
当作本身显然是一个极其备胎的选择,关键就是找到是否有可以替代的最短border。
注意到,fnxtif_{nxt_i}fnxti 已经可以覆盖 [1,nxti][1,nxt_i][1,nxti],那么它只要也可以覆盖后面的部分,那么就可以直接令 fi←fnxtif_i\gets f_{nxt_i}fi←fnxti。
而对于小于 fnxtif_{nxt_i}fnxti 的border,根据定义,其连 [1,nxti][1,nxt_i][1,nxti] 都无法覆盖,所以必然是非法的。
对于大于 fnxtif_{nxt_i}fnxti 的border,假设其合法,那么注意到 fnxtif_{nxt_i}fnxti 必然也可以印出这个border,那么它就可以“仿印”出大 border 的效果,fnxtif_{nxt_i}fnxti 必然也是合法的。所以较大的border即使合法,也必然不会成为最优答案。
所以只需要考虑 fnxtif_{nxt_i}fnxti 是否可以赋值给 fif_ifi 就行了。
可以开桶简单维护。
然而懒得写,还是贴的自己nxt树的做法。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned ll
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}const int N=5e5+100;
const int mod=998244353;inline ll ksm(ll x,ll k){ll res(1);while(k){if(k&1) res=res*x%mod;x=x*x%mod;k>>=1;}return res;
}int n,m,q;char s[N];
int p[N];
void kmp(char *s,int n){p[1]=0;for(int i=1,j=0;i<=n;i++){while(j&&s[j+1]!=s[i+1]) j=p[j];if(s[j+1]==s[i+1]) ++j;p[i+1]=j;}return;
}
int a[N],num,tag[N];
vector<int>e[N],v[N];
int fa[N],vis[N],siz[N],cur;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void merge(int x,int y){x=find(x);y=find(y);if(siz[x]>siz[y]) swap(x,y);fa[x]=y;siz[y]+=siz[x];return;
}
void dfs(int x,int rt){v[rt].push_back(x);tag[x]=1;for(int to:e[x]){if(tag[to]) continue;dfs(to,rt);}return;
}
inline void ins(int x){vis[x]=1;if(vis[x-1]) merge(x-1,x);if(vis[x+1]) merge(x+1,x);cur=max(cur,siz[find(x)]);
}signed main(){
#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);
#endifscanf("%s",s+1);n=strlen(s+1);kmp(s,n);for(int x=n;x;x=p[x]){tag[x]=1;a[++num]=x;}for(int i=1;i<=n;i++){e[p[i]].push_back(i);fa[i]=i;siz[i]=1;}reverse(a+1,a+1+num);//printf("%s\n",s+1);for(int i=1;i<=num;i++) dfs(a[i],a[i]);for(int i=1;i<=n;i++){if(!tag[i]) ins(i);}for(int i=1;i<=num;i++){int x=a[i];if(x>cur){printf("%d\n",x);return 0;} for(int o:v[x]) ins(o); }return 0;
}
/**/