「十二省联考 2019」字符串问题 解题报告

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

当场就去世了,我这菜人改了一下午


考虑一个A,B之间的连边实际表示了两个A之间的有向边,然后把A的连边处理好,就转成了拓扑排序找环+最长链

但是边数很多,考虑优化连边

A,B之间的连边显然没法优化的,考虑一个B可以表示所有它的后缀A

把串反向建出SAM,然后一个B的后缀就是par树的子树

可以拿倍增定位

好了这题就没了

注意到一个事情,定位的点可能重复,于是对SAM拆点,每个点挂一个vector表示一个A或者B的点在SAM的这个位置

然后考虑如何连边

一个B所可以代表的A的集合就是B所在位置的vector中长度不小于Ta的A以及par子树中的A

可以对每个点的vector排序,然后每个B连后面的A,直到下一个B出现或者末尾。

每个末尾的B像par树儿子的开头连边

然后A,B之间的连边照连

之后跑topo就可以了

复杂度\(O(n\log n)\),瓶颈在倍增和清空SAM


Code:

#include <cstdio>
#include <cctype>
#include <cstring>
#include <vector>
#include <algorithm>
#define ll long long
const int N=8e5+10;
template <class T>
void read(T &x)
{
	x=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
int head[N],to[N<<1],Next[N<<1],in[N],cnt;
void add(int u,int v)
{
    ++in[v],to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;
}
int ch[N][26],len[N],par[N],tot=1,las=1;
void extend(int c)
{
	int now=++tot,p=las;
	len[now]=len[p]+1;
	while(p&&!ch[p][c]) ch[p][c]=now,p=par[p];
	if(!p) par[now]=1;
	else
	{
		int x=ch[p][c];
		if(len[x]==len[p]+1) par[now]=x;
		else
		{
			int y=++tot;
			par[y]=par[x];
			len[y]=len[p]+1;
			memcpy(ch[y],ch[x],sizeof ch[y]);
			while(p&&ch[p][c]==x) ch[p][c]=y,p=par[p];
			par[now]=par[x]=y;
		}
	}
	las=now;
}
int f[20][N];
int Find(int x,int l)
{
	for(int i=19;~i;i--)
		if(len[f[i][x]]>=l)
			x=f[i][x];
    return x;
}
int na,nb,m;
int val[N],posa[N],posb[N];
ll dp[N];
int is[N],tot2,Las[N];
std::vector<int> yuy[N];
void Clear()
{
	for(int i=1;i<=tot2;i++)
	{
		for(int j=0;f[j][i];j++)
			f[j][i]=0;
		in[i]=dp[i]=val[i]=0;
		memset(ch[i],0,sizeof ch[i]);
		par[i]=len[i]=0;
		Las[i]=0;
		head[i]=0;
		is[i]=0;
		yuy[i].clear();
	}
	for(int i=1;i<=na;i++) posa[i]=0;
	for(int i=1;i<=nb;i++) posb[i]=0;
	tot=las=1;
	tot2=cnt=0;
}
char s[N];
int pos[N],tax[N],A[N],q[N];
bool cmp(int a,int b){return val[a]==val[b]?is[a]<is[b]:val[a]<val[b];}
void work()
{
	scanf("%s",s+1);
	int n=strlen(s+1);
	for(int i=n;i;i--) extend(s[i]-'a'),pos[n+1-i]=las;
	for(int i=0;i<=n;i++) tax[i]=0;
	for(int i=1;i<=tot;i++) ++tax[len[i]];
	for(int i=1;i<=n;i++) tax[i]+=tax[i-1];
	for(int i=1;i<=tot;i++) A[tax[len[i]]--]=i;
	for(int i=1;i<=tot;i++)
	{
		int now=A[i];
		f[0][now]=par[now];
		for(int j=1;f[j-1][now];j++)
			f[j][now]=f[j-1][f[j-1][now]];
	}
	read(na);
	tot2=tot;
	for(int l,r,p,i=1;i<=na;i++)
	{
		read(l),read(r);
		l=n+1-l,r=n+1-r;
		p=Find(pos[l],l+1-r);
		yuy[p].push_back(posa[i]=++tot2);
		val[tot2]=l+1-r;
		is[tot2]=1;
	}
 	read(nb);
	for(int l,r,p,i=1;i<=nb;i++)
	{
		read(l),read(r);
		l=n+1-l,r=n+1-r;
		p=Find(pos[l],l+1-r);
		yuy[p].push_back(posb[i]=++tot2);
		val[tot2]=l+1-r;
	}
	for(int i=1;i<=tot;i++)
	{
		std::sort(yuy[i].begin(),yuy[i].end(),cmp);
		int las=i;
		for(int j=0;j<yuy[i].size();j++)
		{
			int now=yuy[i][j];
			add(las,now);
			if(!is[now]) val[now]=0,las=now;
		}
		Las[i]=las;
	}
	for(int i=2;i<=tot;i++)
		add(Las[par[i]],i);
	read(m);
	for(int u,v,i=1;i<=m;i++)
	{
		read(u),read(v);
		u=posa[u],v=posb[v];
		add(u,v);
	}
	int l=1,r=0;
	ll mx=0;
	for(int i=1;i<=tot2;i++)
		if(!in[i])
			q[++r]=i,mx=mx>val[i]?mx:val[i],dp[i]=val[i];
	while(l<=r)
	{
		int now=q[l++];
		for(int i=head[now];i;i=Next[i])
		{
			int v=to[i];
			--in[v];
			dp[v]=std::max(dp[v],dp[now]+val[v]);
            mx=mx>dp[v]?mx:dp[v];
			if(!in[v]) q[++r]=v;
		}
	}
	for(int i=1;i<=tot2;i++)
		if(in[i])
		{
			puts("-1");
			Clear();
			return;
		}
	printf("%lld\n",mx);
	Clear();
}
int main()
{
	int T;read(T);
	while(T--) work();
	return 0;
}

2019.4.9

posted @ 2019-04-09 17:38  露迭月  阅读(427)  评论(0编辑  收藏  举报