zoukankan      html  css  js  c++  java
  • Codeforces 700E Cool Slogans

    Codeforces 700E Cool Slogans

    题目大意:给出一个字符串 (S),让你构造一个序列 (S_1,S_2dots S_k),满足 (forall S_i) (S_i)(S) 的字串,且对于 (i > 1)(S_i)(S_{i-1}) 中出现了至少两次,最大化 (k) 的长度。(|S|leq 2 imes 10^5)

    解题思路

    可以证明一个很牛逼的结论,对于 ( ext{parents}) 树上的一个节点 (u) ,其在其子树中的任意节点 (v) 代表的串 (maxv) ,节点 (u) 代表的所有串在 (maxv) 中的所有串出现次数相同。

    假设有两个串出现次数不同,那么一定存在一个出现位置使得 (u​) 代表的一个串 (k​)(maxv​) 的前缀但是 (maxu) 不是,这样会发现 (maxu​)(k​)( ext{right}​) 集合不同,矛盾。

    那么有了这个结论每个节点随便选个长度代表它都是一样的,显然每个串选 (maxu) 对于其祖先来说最优,然后就可以在 (parent) 拿节点做状态了。

    贪心地从后往前做,相当于在 (parent) 树从根往下做能放就放,正确性显然。令 (f[u]) 表示当前考虑到 (u) 节点的最长答案,那么只需要判断 (u) 节点的 (max) 能否放在上一个选的串前面即可。由于 (right) 集合是一个等价类,那么对于每个串的所有出现位置只需要取最前面一个即可,然后用线段树合并维护 (right) 集合判断上一个串是否出现两次即可。由于上一个串是 (u) 的一个祖先,还需要记一下上一个选的串对应节点是什么,复杂度 (O(|S|logn))

    code

    /*program by mangoyang*/
    #include <bits/stdc++.h>
    #define inf (0x7f7f7f7f)
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    typedef long long ll;
    using namespace std;
    template <class T>
    inline void read(T &x){
    	int ch = 0, f = 0; x = 0;
    	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    	for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    	if(f) x = -x;
    }
    const int N = 400005;
    char s[N]; int n, ans;
    namespace Seg{
    	#define mid ((l + r) >> 1)
    	int lc[N*25], rc[N*25], sz[N*25], size;
    	inline void ins(int &u, int l, int r, int pos){
    		if(!u) u = ++size;
    		if(l == r) return (void) (sz[u]++);
    		if(pos <= mid) ins(lc[u], l, mid, pos);
    		else ins(rc[u], mid + 1, r, pos); 
    		sz[u] = sz[lc[u]] + sz[rc[u]];
    	}
    	inline int merge(int x, int y, int l, int r){
    		if(!x || !y) return x + y;
    		int o = ++size;
    		if(l == r) sz[o] = sz[x] + sz[y];
    		else{
    			lc[o] = merge(lc[x], lc[y], l, mid);
    			rc[o] = merge(rc[x], rc[y], mid + 1, r);
    			sz[o] = sz[lc[o]] + sz[rc[o]];
    		}
    		return o;
    	}
    	inline int query(int u, int l, int r, int L, int R){
    		if(l >= L && r <= R) return sz[u];
    		int res = 0;
    		if(L <= mid) res += query(lc[u], l, mid, L, R);
    		if(mid < R) res += query(rc[u], mid + 1, r, L, R);
    		return res;
    	}
    	#undef mid
    }
    namespace SAM{
    	vector<int> g[N];
    	int ch[N][26], id[N], len[N], fa[N], dp[N], rt[N], pos[N], tail = 1, size = 1;
    	inline int newnode(int x){ return len[++size] = x, size; }
    	inline void ins(int c, int x){
    		int p = tail, np = newnode(len[p] + 1); pos[np] = x;
    		Seg::ins(rt[np], 1, n, pos[np]);
    		for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
    		if(!p) return (void) (fa[np] = 1, tail = np);
    		int q = ch[p][c];
    		if(len[q] == len[p] + 1) fa[np] = q;
    		else{
    			int nq = newnode(len[p] + 1); pos[nq] = x;
    			fa[nq] = fa[q], fa[q] = fa[np] = nq;
    			for(int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
    			for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
    		}tail = np;
    	}
    	inline void addedge(){
    		for(int i = 2; i <= size; i++) g[fa[i]].push_back(i);
    	}
    	inline void dfs(int u){
    		for(int i = 0; i < (int) g[u].size(); i++)
    			dfs(g[u][i]), rt[u] = Seg::merge(rt[u], rt[g[u][i]], 1, n);
    	}
    	inline void dfs2(int u){
    		if(u > 1){
    			if(fa[u] == 1) id[u] = u, dp[u] = 1;
    			else{
    				int tmp = Seg::query(rt[id[fa[u]]], 1, n, pos[u] - len[u] + len[id[fa[u]]], pos[u] - 1);
    				if(tmp) dp[u] = dp[fa[u]] + 1, id[u] = u; else dp[u] = dp[fa[u]], id[u] = id[fa[u]]; 			
    			}
    		}
    		ans = max(ans, dp[u]);
    		for(int i = 0; i < (int) g[u].size(); i++) dfs2(g[u][i]);
    	}
    }
    int main(){
    	read(n), scanf("%s", s + 1);
    	for(int i = 1; i <= n; i++)
    		SAM::ins(s[i] - 'a', i);
    	SAM::addedge(), SAM::dfs(1), SAM::dfs2(1);
    	cout << ans << endl;
    	return 0;
    }
    
  • 相关阅读:
    RTF文件格式
    javascript 正则表达式基础
    不同线程之间传递数据
    JavaScript trim函数
    Simple Editor
    关于RichTextBox字体的问题
    手机短信自动清理方式
    手机来电显示新方法
    具有二维码自动识别功能的交通标志
    利用手机扫描二维码技术识别房屋租赁信息
  • 原文地址:https://www.cnblogs.com/mangoyang/p/10409198.html
Copyright © 2011-2022 走看看