十二省联考 字符串问题

Description

传送门


Solution

显然是建图跑最长路一类的问题,我们需要将Bx类串连向Ay,仅当BxAy的前缀时成立。而所有的A类串和B类串均选自同一大串s,故若将s的后缀树建出来,这种前缀关系就很好在后缀树上表示出来了。

后缀树上对于点u,它可以做它所有子节点的前缀。

而构造目标串的过程是:先选择一个A类串,然后可以通过这个Ai所支配的B类串Bx的后面接上一个Aj,满足Aj的前缀是Bx,重复上述过程直到无可匹配。

那么随便怎么建一下图就可以了。

至于构造的目标串能否无限长,只需要看建出的图有没有环即可。

务必用拓扑排序实现。Spfa只有暴力分


code_by_uselessName

#pragma G++ optimize(2)
#pragma GCC optimize(2)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#define GET getchar()
#define LL long long
using namespace std;

namespace FastIO{
	inline int read(){
		int s=0,f=1;char t=GET;
		while('0'>t||t>'9'){if(t=='-')f=-1;t=GET;}
		while('0'<=t&&t<='9'){s=(s<<1)+(s<<3)+t-'0';t=GET;}
		return s*f;
	}
}
using FastIO::read;

const int N=200005;
const int M=2000005;
const int An=400005;
const int Am=26;
const int lim=19;
int n,na,nb,tot,Bac[An];
LL dp[M];
int Ina[N],Outa[N],Inb[N],Outb[N];
int prt[An][20];

struct Node{
	int len,fla,id;
};

bool cmp(Node a,Node b){
	if(a.len!=b.len)return a.len<b.len;
	return a.fla>b.fla;
}

vector<Node>Inf[An];

namespace SuffixAuto{
	int root,lst,cnt,len[An],ch[An][Am],fle[N],fa[An],sum[N],sa[An];
	int Make(int _len){
		len[++cnt]=_len;
		return cnt;
	}
	void Init(){
		root=lst=Make(0);
	}
	void Insert(int v,int _pos){
		int p=lst,_id=Make(len[p]+1);fle[_pos]=lst=_id;
		while(p&&(!ch[p][v]))ch[p][v]=_id,p=fa[p];
		if(!p)fa[_id]=root;
		else{
			int Nxt=ch[p][v];
			if(len[p]+1==len[Nxt])fa[_id]=Nxt;
			else{
				int rep=Make(len[p]+1);
				for(int i=0;i<26;i++)ch[rep][i]=ch[Nxt][i];
				fa[rep]=fa[Nxt];fa[Nxt]=fa[_id]=rep;
				while(p&&ch[p][v]==Nxt)ch[p][v]=rep,p=fa[p];
			}
		}
	}
	void Topsort(){
		memset(sum,0,sizeof(sum));
		for(int i=1;i<=cnt;i++)sum[len[i]]++;
		for(int i=1;i<=n;i++)sum[i]+=sum[i-1];
		for(int i=1;i<=cnt;i++)sa[sum[len[i]]--]=i;
	}
}
using namespace SuffixAuto;

struct line{
	int Nxt,to,val;
}l[M];
int h[M],lcnt,In[M];

void Link(int u,int v,int w){
	l[++lcnt]=(line){h[u],v,w};h[u]=lcnt;In[v]++;
}

int Topsum;
void __Topsort(){
	queue<int>q;
	for(int i=1;i<=tot;i++)if(!In[i])q.push(i);
	while(q.size()){
		int u=q.front();q.pop();Topsum++;
		for(int i=h[u],v;i;i=l[i].Nxt){
			v=l[i].to;
			dp[v]=max(dp[v],dp[u]+l[i].val);
			if(!(--In[v]))q.push(v);
		}
	}
}

void buildGraph(){
	tot=cnt;Topsort();
	for(int i=1;i<=na;i++)Ina[i]=++tot,Outa[i]=++tot;
	for(int i=1,u;i<=cnt;i++){
		u=sa[i];Bac[u]=u;
		if(fa[u])Link(Bac[fa[u]],u,0);
		if(Inf[u].size()){
			sort(Inf[u].begin(),Inf[u].end(),cmp);
			for(int j=0,id;j<Inf[u].size();j++){
				id=Inf[u][j].id;
				if(Inf[u][j].fla==1){
					Link(Bac[u],Ina[id],0);
					Link(Ina[id],Outa[id],Inf[u][j].len);
				}
				else Link(Bac[u],Inb[id]=Outb[id]=++tot,0),Bac[u]=tot;
			}
		}
	}
	int m=read();
	for(int i=1,a,b;i<=m;i++){
		a=read();b=read();
		Link(Outa[a],Inb[b],0);
	}
}

void LCAInit(){
	for(int i=1;i<=cnt;i++)prt[i][0]=fa[i];
	for(int j=1;j<=lim;j++)
		for(int i=1;i<=cnt;i++)prt[i][j]=prt[prt[i][j-1]][j-1];
}

void Climb(int pos,Node _Inf){
	pos=fle[pos];
	for(int k=lim;k>=0;k--)if(prt[pos][k]&&len[prt[pos][k]]>=_Inf.len)pos=prt[pos][k];
	Inf[pos].push_back(_Inf);
}

char s[N];

void Clear(){
	for(int u=1;u<=cnt;u++){
		fa[u]=len[u]=prt[u][0]=0;
		Inf[u].clear();
		memset(ch[u],0,sizeof(ch[u]));
	}
	for(int u=1;u<=tot;u++)h[u]=In[u]=dp[u]=0;
	root=cnt=lcnt=tot=Topsum=0;
}

void Solve(){
	scanf("%s",s+1);n=strlen(s+1);Init();
	for(int i=n;i>=1;i--)Insert(s[i]-'a',i);LCAInit();
	na=read();
	for(int i=1,l,r;i<=na;i++){
		l=read();r=read();
		if(l<1||l>r||r>n)l=1,r=0;
		Climb(l,(Node){r-l+1,1,i});
	}
	nb=read();
	for(int i=1,l,r;i<=nb;i++){
		l=read();r=read();
		if(l<1||l>r||r>n)l=1,r=0;
		Climb(l,(Node){r-l+1,2,i});
	}
	buildGraph();
	__Topsort();
	if(Topsum!=tot)cout<<"-1\n";
	else{
		LL Max=0;
		for(int i=1;i<=na;i++)Max=max(Max,dp[Outa[i]]);
		cout<<Max<<'\n';
	}
	Clear();
}

int main(){
	int Case=read();
	while(Case--)Solve();
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 内容概要 《计算机试卷1》是一份综合性的计算机基础和应用测试卷,涵盖了计算机硬件、软件、操作系统、网络、多媒体技术等多个领域的知识点。试卷包括单选题和操作应用两大类,单选题部分测试学生对计算机基础知识的掌握,操作应用部分则评估学生对计算机应用软件的实际操作能力。 ### 适用人群 本试卷适用于: - 计算机专业或信息技术相关专业的学生,用于课程学习或考试复习。 - 准备计算机等级考试或职业资格认证的人士,作为实战演练材料。 - 对计算机操作有兴趣的自学者,用于提升个人计算机应用技能。 - 计算机基础教育工作者,作为教学资源或出题参考。 ### 使用场景及目标 1. **学习评估**:作为学校或教育机构对学生计算机基础知识和应用技能的评估工具。 2. **自学测试**:供个人自学者检验自己对计算机知识的掌握程度和操作熟练度。 3. **职业发展**:帮助职场人士通过实际操作练习,提升计算机应用能力,增强工作竞争力。 4. **教学资源**:教师可以用于课堂教学,作为教学内容的补充或学生的课后练习。 5. **竞赛准备**:适合准备计算机相关竞赛的学生,作为强化训练和技能检测的材料。 试卷的目标是通过系统性的题目设计,帮助学生全面复习和巩固计算机基础知识,同时通过实际操作题目,提高学生解决实际问题的能力。通过本试卷的学习与练习,学生将能够更加深入地理解计算机的工作原理,掌握常用软件的使用方法,为未来的学术或职业生涯打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值