• 【GDOI2020模拟4.11】黑红兔(brr) (SA+字符串性质+可持久化线段树)


    (nle 500000)
    https://gmoj.net/senior/#main/show/6555

    一个发现是我们肯定可以选长度为(1,2,3,…)的一组解。

    那么长度不超过(sqrt {2n}),做一个dp,设(f[i][j])表示(j)为开头,长度为(i),是否可以。
    用hash去找相同的子串,用个指针维护能转移区域的max值,即可做到(O(n sqrt n))

    接下来需要发现更深的性质:
    考虑以(j)开头的,如果有长度为(i)的解,那么也一定有长度为(i-1)的解,所以直接设(f[j])表示以j开头最长是多少。

    从后往前做,对于(f[j])的值,二分(mid),相当于在(kin[j+mid,n])中找一个(k),满足(max(lcp(s[j..n],s[k..n]),lcp[s[j+1..n],s[k..n]])ge mid-1),且(f[k]+1ge mid)

    (lcp)的限制建出(sa)之后就是在一个区间里,至于(kin[j+mid,n]),用可持久化线段树找区间最大值就好了。

    (O(n~log^2~n))还是过不了的。

    类似于(SA)(height)的求法,对(f)显然有(f[j+1]ge f[j]-1->f[j]le f[j+1]+1),这样就不用二分了。


    Code:

    #include<bits/stdc++.h>
    #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
    #define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
    #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
    #define ll long long
    #define pp printf
    #define hh pp("
    ")
    using namespace std;
    
    const int N = 5e5 + 5;
    
    int n;
    char s[N];
    
    int m, sa[N], rk[N], tp[N], tax[N], he[N];
    void rsort() {
    	fo(i, 1, m) tax[i] = 0;
    	fo(i, 1, n) tax[rk[tp[i]]] ++;
    	fo(i, 1, m) tax[i] += tax[i - 1];
    	fd(i, n, 1) sa[tax[rk[tp[i]]] --] = tp[i];
    }
    int cmp(int *f, int x, int y, int z) { return f[x] == f[y] && f[x + z] == f[y + z];}
    int f[20][N];
    void build() {
    	s[n + 1] = -1;
    	fo(i, 1, n) rk[i] = s[i], tp[i] = i;
    	m = 255, rsort();
    	for(int w = 1, p = 0; p < n; w *= 2) {
    		p = 0; fo(i, n - w + 1, n) tp[++ p] = i;
    		fo(i, 1, n) if(sa[i] > w) tp[++ p] = sa[i] - w;
    		m = p, rsort();
    		fo(i, 1, n) tp[i] = rk[i];
    		rk[sa[1]] = p = 1;
    		fo(i, 2, n) rk[sa[i]] = cmp(tp, sa[i - 1], sa[i], w) ? p : ++ p;
    	}
    	int j, k = 0;
    	for(int i = 1; i <= n; he[rk[i ++]] = k) {
    		for(k ? k -- : 0, j = sa[rk[i] - 1]; s[i + k] == s[j + k]; k ++);
    	}
    	fo(i, 1, n) f[0][i] = he[i];
    	fo(j, 1, 19) fo(i, 1, n) {
    		f[j][i] = f[j - 1][i];
    		if(i + (1 << j - 1) <= n) f[j][i] = min(f[j][i], f[j - 1][i + (1 << j - 1)]);
    	}
    //	fo(i, 1, n) {
    //		pp("%d
    ", he[i]);
    //		fo(j, sa[i], n) pp("%c", s[j]);
    //		hh;
    //	}
    }
    
    int qu(int x, int y) {
    	int l = log2(y - x + 1);
    	return min(f[l][x], f[l][y - (1 << l) + 1]);
    }
    
    #define i0 t[i].l
    #define i1 t[i].r
    struct tree {
    	int l, r, x;
    } t[N * 20]; int tt;
    int pl, pr, px;
    void add(int &i, int x, int y) {
    	if(y < pl || x > pr) return;
    	t[++ tt] = t[i]; i = tt;
    	t[i].x = max(t[i].x, px);
    	if(x == y) return;
    	int m = x + y >> 1;
    	add(i0, x, m); add(i1, m + 1, y);
    }
    void ft(int i, int x, int y) {
    	if(!i || y < pl || x > pr) return;
    	if(x >= pl && y <= pr) { px = max(px, t[i].x); return;}
    	int m = x + y >> 1;
    	ft(i0, x, m); ft(i1, m + 1, y);
    }
    
    int g[N], dp[N];
    
    void cx(int x, int v) {
    	pl = x, pr = x;
    	for(int l = 1, r = x - 1; l <= r; ) {
    		int m = l + r >> 1;
    		if(qu(m + 1, x) >= v - 1) pl = m, r = m - 1; else l = m + 1;
    	}
    	for(int l = x + 1, r = n; l <= r; ) {
    		int m = l + r >> 1;
    		if(qu(x + 1, m) >= v - 1) pr = m, l = m + 1; else r = m - 1;
    	}
    }
    
    int pd(int i, int v) {
    	px = 0;
    	if(i + v <= n) {
    		cx(rk[i], v);
    		ft(g[i + v], 1, n);
    		if(i < n) {
    			cx(rk[i + 1], v);
    			ft(g[i + v], 1, n);
    		}
    	}
    	return px + 1 >= v;
    }
    
    void work() {
    	int ans = 0;
    	fd(i, n, 1) {
    		dp[i] = dp[i + 1] + 1;
    		while(!pd(i, dp[i])) dp[i] --;
    		ans = max(ans, dp[i]);
    		g[i] = g[i + 1];
    		pl = pr = rk[i]; px = dp[i];
    		add(g[i], 1, n);
    	}
    	pp("%d
    ", ans);
    }
    
    int main() {
    	freopen("brr.in", "r", stdin);
    	freopen("brr.out", "w", stdout);
    	scanf("%s", s + 1);
    	n = strlen(s + 1);
    	build();
    	work();
    }
    
  • 相关阅读:
    输入url后的加载过程~
    编写一个方法,求字符串长度~~~
    闭包 什么是闭包 为什么用闭包~~
    作用域链的理解~~
    谈谈javascript的基本规范~~~~
    html中datalist 是什么??????
    elementui中el-input联想搜索框
    js中数组对象去重的方法
    vue视频截图第一帧demo
    styled-components的基本使用
  • 原文地址:https://www.cnblogs.com/coldchair/p/12679432.html
Copyright © 2020-2023  润新知