P5284 [十二省联考2019]字符串问题

题解

这道题目也太重工业了吧。。。

胡题 (20 min) ,写题 (5 days) ,还没写出来 ,我只能爪巴。

不想调了,写篇题解记录一下思路。

就是你给反串建出 ( ext{SAM}) 之后在考虑直接在树上建图,然后跑一个 ( ext{top}) 就可以了。

代码

(0pts) ,样例都过了,想调的人可以帮我调一下。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=4e5+5;
int ls,na,nb,m,id[N];char s[N];
struct Sub{int l,r,len;}a[N],b[N];
int tot=0,tag[N][2],f[N<<1],res;
struct Tree{
	struct Edge{int nxt,from,to;}e[N<<1];int fir[N<<1],deg[N<<1],size=0;
	void add(int u,int v){e[++size]=(Edge){fir[u],u,v},deg[v]++,fir[u]=size;}
}t1,t2;
struct SAM{
	int tot,lst;
	struct Node{
		int len,fa[20],go[26];
		vector<pair<int,pair<int,int> > > bag;
	}tr[N<<1];
	void clear(){
		tot=lst=1;
		for(int i=0;i<(N<<1);++i){
			tr[i].len=tr[i].fa[0]=0,tr[i].bag.clear();
			memset(tr[i].go,0,sizeof(tr[i].go));
		}
	}
	void insert(int x){
		int u=lst,now=lst=++tot;
		tr[now].len=tr[u].len+1;
		while(u&&!tr[u].go[x])
		tr[u].go[x]=now,u=tr[u].fa[0];
		if(!u) return tr[now].fa[0]=1,void();
		int v=tr[u].go[x];
		if(tr[u].len+1==tr[v].len)
		return tr[now].fa[0]=v,void();
		int w=++tot;tr[w]=tr[v];
		tr[w].len=tr[u].len+1;
		tr[v].fa[0]=tr[now].fa[0]=w;
		while(u&&tr[u].go[x]==v)
		tr[u].go[x]=w,u=tr[u].fa[0];
	}
}sam;
void dfs(int u,int anc){
	sort(sam.tr[u].bag.begin(),sam.tr[u].bag.end());
	for(int i=0;i<(int)sam.tr[u].bag.size();++i){
		pair<int,pair<int,int> > tmp=sam.tr[u].bag[i];
		if(i&&tmp.first==sam.tr[u].bag[i-1].first)
		tag[tmp.second.first][tmp.second.second]=tot;
		else{
			tag[tmp.second.first][tmp.second.second]=++tot;
			if(anc) t2.add(anc,tot),anc=tot;
		}
	}
	for(int i=t1.fir[u];i;i=t1.e[i].nxt) dfs(t1.e[i].to,anc);
}
void init(){
	tot=t1.size=t2.size=res=0;
	memset(s,0,sizeof(s));
	memset(tag,0,sizeof(tag));
	memset(t1.fir,0,sizeof(t1.fir));
	memset(t1.deg,0,sizeof(t1.deg));
	memset(t2.fir,0,sizeof(t2.fir));
	memset(t2.deg,0,sizeof(t2.deg));
	for(int i=0;i<(N<<1);++i) f[i]=-1e18-7;
	sam.clear();
}
bool top(){
	queue<int> q;
	f[tot+na+1]=0,q.push(tot+na+1);
	for(int i=1;i<=tot+na;++i) if(!t2.deg[i]) q.push(i);
	while(!q.empty()){
		int u=q.front();q.pop();
		res=max(res,f[u]);
		// printf("%lld %lld
",u,f[u]);
		for(int i=t2.fir[u];i;i=t2.e[i].nxt){
			int v=t2.e[i].to;t2.deg[v]--;
			if(v<=tot) f[v]=max(f[v],f[u]);
			else f[v]=max(f[v],f[u]+a[v-tot].len);
			if(!t2.deg[v]) q.push(v);
		}
	}
	for(int i=1;i<=tot+na+1;++i) if(t2.deg[i]) return false;
	return true;
}
void solve(){
	scanf("%s",s+1),ls=strlen(s+1);
	for(int i=ls;i>=1;--i){
		sam.insert(s[i]-'a');
		id[ls-i+1]=sam.tot;
	}
	for(int i=2;i<=sam.tot;++i){
		t1.add(sam.tr[i].fa[0],i);
	}
	for(int j=1;j<20;++j){
		for(int i=1;i<=sam.tot;++i)
		sam.tr[i].fa[j]=sam.tr[sam.tr[i].fa[j-1]].fa[j-1];
	}
	scanf("%lld",&na);
	for(int i=1;i<=na;++i){
		scanf("%lld%lld",&a[i].r,&a[i].l);
		a[i].l=ls-a[i].l+1,a[i].r=ls-a[i].r+1;
		int u=id[a[i].r];a[i].len=a[i].r-a[i].l+1;
		for(int j=19;j>=0;--j){
			if(sam.tr[sam.tr[u].fa[j]].len>=a[i].len)
			u=sam.tr[u].fa[j];
		}
		sam.tr[u].bag.push_back(make_pair(a[i].len,make_pair(i,0)));
	}
	scanf("%lld",&nb);
	for(int i=1;i<=nb;++i){
		scanf("%lld%lld",&b[i].r,&b[i].l);
		b[i].l=ls-b[i].l+1,b[i].r=ls-b[i].r+1;
		int u=id[b[i].r];b[i].len=b[i].r-b[i].l+1;
		for(int j=19;j>=0;--j){
			if(sam.tr[sam.tr[u].fa[j]].len>=b[i].len)
			u=sam.tr[u].fa[j];
		}
		sam.tr[u].bag.push_back(make_pair(b[i].len,make_pair(i,1)));
	}
	dfs(1,0);
	for(int i=1;i<=na;++i){
		t2.add(tot+na+1,tot+i);
		t2.add(tag[i][0],tot+i);
	}
	scanf("%lld",&m);
	for(int i=1;i<=m;++i){
		int u,v;scanf("%lld%lld",&u,&v);
		t2.add(tot+u,tag[v][1]);
	}
	// for(int i=1;i<=t2.size;++i){
	// 	printf("%lld %lld
",t2.e[i].from,t2.e[i].to);
	// }
	return printf("%lld
",top()?res:-1ll),void();
}
signed main(){
	int T;cin>>T;
	while(T--) init(),solve();
}
/*
1
abbaabbaab
4
1 5
4 7
6 9
8 10
3
1 6
10 10
4 6
5
1 2
1 3
2 1
3 3
4 1
*/
原文地址:https://www.cnblogs.com/Point-King/p/14648167.html