「十二省联考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
原文地址:https://www.cnblogs.com/roal-l/p/13086099.html