• 「十二省联考2019」 字符串问题


    Description

    给出一个字符串(S)和若干个(A)类串和(B)类串,保证两类串都是(S)的子串,并且在给出若干组支配关系((x,y))表示一个编号为(x)(A)类串支配编号为(y)(B)类串,现在你需要求出一个长度最长的(T)串满足(T)可以被划分为若干个(A)类串,并且第(i)(A)类串存在一个支配的(B)类串是第(i+1)(A)类串的前缀

    Solution

    考虑我们如果将一个(B)类串向所有该串是其前缀的(A)类串连边,然后在将支配关系连边,那么我们得到的必定是一个(DAG),否则无解,所以只需要对其进行一遍拓扑排序(DP)就好了

    考虑怎么进行连边,这里首先考虑对反串建出一个(SAM),那么一个(B)类串就只需要向他在(parent)树上的子树中所有(A)类串连边就好了,但是由于会存在某些(A)类串和(B)类串在同一个点上,所以我们需要将这些点按照串长将他从(parent)树中拆出来就好了,最后子树连边直接做一遍(DFS)序然后线段树优化建图即可,复杂度(O(nlog n+mlog n))

    事实上还有一种优秀的建图方式,就是考虑每个(A)类串直接由离他最近的一个祖先(B)类串连边就好了,这样就可以将点数和边数都做到(O(n))

    Code

    //Created Time:2020年05月04日 星期一 20时50分42秒
    #include <queue>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define N 1000006
    #define pi pair<int, int>
    #define fi first
    #define se second
    #define mkp make_pair
    #define pb push_back
    
    using namespace std;
    
    void chmax(long long &x, long long y){x = x >= y ? x : y;}
    
    int n, na, nb, m, tot, num;
    int pos[N], ida[N], idb[N], lena[N], lenb[N], sz[N], dfn[N], book[N], id[N], deg[N];
    char s[N];
    long long dis[N];
    
    vector<pi> nd[N], e[N];
    vector<int> son[N];
    
    int read();
    void work();
    bool cmp(pi ,pi);
    void build(int ,int ,int);
    void link(int ,int ,int ,int ,int, int);
    
    //{{{SAM
    struct SAM{
    	int cnt, lst;
    	int fa[N], len[N], ch[N][26], d[N], rk[N], fath[N][20];
    
    	void clear(){
    		for(int i = 1; i <= cnt; ++i){
    			id[i] = dfn[i] = sz[i] = book[i] = d[i] = fa[i] = len[i] = 0;
    			memset(ch[i], 0, sizeof ch[i]);
    			memset(fath[i], 0, sizeof fath[i]);
    			vector<pi>().swap(nd[i]);
    			vector<int>().swap(son[i]);
    		}
    		cnt = lst = 1; tot = 0;
    		return ;
    	}
    
    	int ins(int x){
    		int np = ++cnt, p = lst; lst = np; len[np] = len[p] + 1;
    		for(; p && !ch[p][x]; p = fa[p]) ch[p][x] = np;
    		if(!p) fa[np] = 1;
    		else{
    			int q = ch[p][x];
    			if(len[q] == len[p] + 1) fa[np] = q;
    			else{
    				int nq = ++cnt; memcpy(ch[nq], ch[q], sizeof ch[nq]);
    				fa[nq] = fa[q]; fa[q] = fa[np] = nq; len[nq] = len[p] + 1;
    				for(; p && ch[p][x] == q; p = fa[p]) ch[p][x] = nq;
    			}
    		}
    		return np;
    	}
    
    	void get(){
    		for(int i = 1; i <= cnt; ++i) ++d[len[i]];
    		for(int i = 1; i <= cnt; ++i) d[i] += d[i - 1];
    		for(int i = cnt; i >= 1; --i) rk[d[len[i]]--] = i;
    		for(int i = 1; i <= cnt; ++i){
    			int u = rk[i]; fath[u][0] = fa[u];
    			for(int j = 1; j <= 19; ++j)
    				fath[u][j] = fath[fath[u][j - 1]][j - 1];
    		}
    		return ;
    	}
    
    	void find(int u, int x, int flag){
    		for(int i = 19; ~i; --i)
    			if(len[fath[u][i]] >= (flag ? lena[x] : lenb[x]))
    				u = fath[u][i];
    		nd[u].pb(mkp(x, flag));
    		return ;
    	}
    
    	void dfs(int u){
    		dfn[u] = tot;
    		if(book[u] >= 2) dfn[u] = ++tot, sz[u] = 1, lena[tot] = len[u];
    		for(auto v : son[u])
    			dfs(v), sz[u] += sz[v];
    		return ;
    	}
    
    
    	void rebuild(){
    		for(int i = 1; i <= cnt; ++i){
    			if(nd[i].empty()) continue;
    			sort(nd[i].begin(), nd[i].end(), cmp);
    			int lst = fa[i];
    			for(auto p : nd[i]){
    				int u = p.fi, op = p.se;
    				if(len[lst] == (op ? lena[u] : lenb[u]) && book[lst] != op + 1) book[lst] = 3;
    				else if(len[lst] != (op ? lena[u] : lenb[u])){
    					fa[++cnt] = lst; len[cnt] = op ? lena[u] : lenb[u];
    					book[cnt] = op + 1; lst = cnt;
    				}
    				(op ? ida[u] : idb[u]) = lst;
    				continue;
    			}
    			fa[i] = lst;
    		}
    		for(int i = 1; i <= cnt; ++i) son[fa[i]].push_back(i);
    		dfs(1); return ;
    	}
    }sam;
    //}}}
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("a.in", "r", stdin);
        freopen("a.out", "w", stdout);
    #endif
    	int T; cin >> T;
    	while(T--)
    		work();
    	return 0;
    }
    
    int read(){
    	int x = 0; char ch = getchar();
    	for(; !isdigit(ch); ch = getchar());
    	for(; isdigit(ch); ch = getchar()) x = x * 10 + (ch - '0');
    	return x;
    }
    
    bool cmp(pi x, pi y){
    	int lenx = x.se ? lena[x.fi] : lenb[x.fi];
    	int leny = y.se ? lena[y.fi] : lenb[y.fi];
    	return lenx < leny;
    }
    
    void work(){
    	scanf("%s", s + 1); n = strlen(s + 1);
    	sam.clear(); long long ans = 0;
    	for(int i = n; i; --i) pos[i] = sam.ins(s[i] - 'a');
    	na = read(); sam.get();
    	for(int i = 1; i <= na; ++i){
    		int l = read(), r = read();
    		lena[i] = r - l + 1;
    		chmax(ans, lena[i] * 1ll);
    		sam.find(pos[l], i, 1);
    	}
    	nb = read();
    	for(int i = 1; i <= nb; ++i){
    		int l = read(), r = read();
    		lenb[i] = r - l + 1;
    		sam.find(pos[l], i, 0);
    	}
    	num = 0; sam.rebuild();
    	build(1, 1, tot);
    	int lim = num;
    	for(int i = 1; i <= nb; ++i){
    		int u = idb[i]; idb[i] = ++num;
    		if(book[u] != 3)
    			link(1, 1, tot, dfn[u] + 1, dfn[u] + sz[u], num);
    		else link(1, 1, tot, dfn[u], dfn[u] + sz[u] - 1, num);
    	}
    	m = read();
    	for(int i = 1; i <= m; ++i){
    		int x = read(), y = read();
    		e[id[dfn[ida[x]]]].pb(mkp(idb[y], 0));
    		++deg[idb[y]];
    	}
    	queue<int> Q;
    	for(int i = 1; i <= num; ++i){
    		dis[i] = 0;
    		if(!deg[i]){
    			if(i > lim) dis[i] = -999999999;
    			Q.push(i);
    		}
    	}
    	int cnt = 0;
    	while(!Q.empty()){
    		int u = Q.front(); Q.pop(); ++cnt;
    		chmax(ans, dis[u]);
    		for(auto p : e[u]){
    			int v = p.fi, w = p.se;
    			chmax(dis[v], dis[u] + w);
    			--deg[v];
    			if(!deg[v]) Q.push(v);
    		}
    	}
    	if(cnt != num) puts("-1");
    	else printf("%lld
    ", ans);
    	for(int i = 1; i <= num; ++i) 
    		vector<pi>().swap(e[i]), deg[i] = 0;
    	return ;
    }
    
    #define ls pos << 1
    #define rs pos << 1 | 1
    void build(int pos, int l, int r){
    	num = max(num, pos);
    	if(l == r) return id[l] = pos, void();
    	int mid = (l + r) >> 1;
    	build(ls, l, mid); build(rs, mid + 1, r);
    	if(l == mid) e[pos].pb(mkp(ls, lena[l]));
    	else e[pos].pb(mkp(ls, 0)); 
    	if(mid + 1 == r) e[pos].pb(mkp(rs, lena[r]));
    	else e[pos].pb(mkp(rs, 0));
    	++deg[ls]; ++deg[rs];
    	return ;
    }
    
    void link(int pos, int l, int r, int nl, int nr, int p){
    	if(nl > nr) return ;
    	if(l >= nl && r <= nr){
    		++deg[pos];
    		if(l == r) 
    			e[p].pb(mkp(pos, lena[l]));
    		else e[p].pb(mkp(pos, 0));
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if(mid >= nl) link(ls, l, mid, nl, nr, p);
    	if(mid < nr) link(rs, mid + 1, r, nl, nr, p);
    	return ;
    }
    #undef ls
    #undef rs
    
  • 相关阅读:
    vscode中执行gulp task的简便方法
    5G即将到来,你还会购买4G手机吗?
    小屏幕手机汇总
    NoSQL数据库的分布式算法详解
    如何在网页界面设计中正确的留出空白空间?
    iconfont的三种使用方式
    MySQL修改密码方法汇总
    Docker镜像与容器
    微观经济学
    经营的原点 书评
  • 原文地址:https://www.cnblogs.com/roal-l/p/13086099.html
Copyright © 2020-2023  润新知