1. 程式人生 > 其它 >【題解】[LNOI2022] 串

【題解】[LNOI2022] 串

\(T_0\)\(S\) 的子串;

\(\forall 1 \le i \le l\)\(\lvert T_i \rvert - \lvert T_{i - 1} \rvert = 1\)

\(\forall 1 \le i \le l\),存在 \(S\) 的一個長度為 \(\lvert T_i \rvert + 1\) 的子串 \(S'_i\),使得 \(S'_i\) 的長度為 \(\lvert T_{i - 1} \rvert\) 的字首為 \(T_{i - 1}\),長度為 \(\lvert T_i \rvert\) 的字尾為 \(T_i\)

求最大的 \(l\)

看起來這個限制條件非常怪異,我們手動模擬一下,發現就是擴充套件串的過程。從當前串 \([l,r]\)

,刪除第一個位置,向後擴充套件兩個位置,得到 \([l + 1, r + 2]\)

所以我們肯定是從空串開始擴充套件最優,直接從 \(S\) 開始擴充套件可以得到 \(|S|/2\) 的答案。

考慮存在兩個子串相同的情況,比如 \([l_1,r_1]\)\([l_2, r_2]\),不妨設 \(l1 < l2\),那麼我們擴充套件到 \([l_2,x] (x \le r_2)\) 後,可以跳到 \([l_1,r_1]\) 繼續向後擴充套件,然後再次到達 \(l_2\),跳回到 \(l_1\)。一直持續到長度 \(> r - l + 1\) 結束。

那麼最優的情況就是跳回到 \([l_1,r_1]\)

時,長度恰好為 \(r-l+1\),此時答案是 \(r - l + 1 + \left\lfloor\dfrac{|S| - r}{2}\right\rfloor\)

如果使用多對相同的子串呢?我們觀察到最優情況下,長度恰好取到 \(r-l+1\) 且一定能取到,所以使用多對子串不會比只使用最後一對子串更優,所以只用考慮一對相同子串的情況。

這些都可以使用字尾自動機快速求出,時間複雜度 \(\mathcal{O}(|S|)\)

#define N 1000005
struct SAM{
	int fa[N], nxt[N][26], sz[N], len[N], w[N], lst, idx;
	void init(){
		rep(i, 0, idx)
			fa[i] = sz[i] = w[i] = 0, memset(nxt[i], 0, sizeof(nxt[i]));
		fa[0] = ~0, lst = idx = 0;
	}
	void extend(int ch){
		int cur = ++idx, p = lst; len[cur] = w[cur] = len[p] + 1;
		while(~p && !nxt[p][ch])nxt[p][ch] = cur, p = fa[p];
		if(-1 == p)fa[cur] = 0;
		else{
			int q = nxt[p][ch];
			if(len[p] + 1 == len[q])fa[cur] = q;
			else{
				int now = ++idx; len[now] = len[p] + 1, w[now] = w[q];
				rep(i, 0, 25)nxt[now][i] = nxt[q][i];
				fa[now] = fa[q], fa[q] = fa[cur] = now;
				while(~p && nxt[p][ch] == q)nxt[p][ch] = now, p = fa[p];
			}
		}sz[lst = cur]++;
	}
	int c[N], b[N];
	void calc(){
		rp(i, idx)c[i] = 0;
		rp(i, idx)c[len[i]]++;
		rp(i, idx)c[i] += c[i - 1];
		rp(i, idx)b[c[len[i]]--] = i;
		pr(i, idx)sz[fa[b[i]]] += sz[b[i]];
		int n = len[lst], ans = n / 2;
		rp(i, idx)if(sz[i] > 1)cmx(ans, len[i] + (n - w[i]) / 2);
		printf("%d\n", ans);
	}
}w;
char s[N];
int main() {
	int T; read(T);
	while(T--){
		w.init();
		scanf("%s", s + 1);
		int n = strlen(s + 1);
		rp(i, n)w.extend(s[i] - 'a');
		w.calc();
	}
	return 0;
}