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


    题目

    其实是一道熟练的套路题啊

    之后我由于树上倍增没加(1)而熟练保龄

    首先(SA)做这道题是肯定可以的,我们二分+(St)表就可以求出每一个(B)串的扩展区间(就是这个区间内的后缀和这个串的(lcp)都大于等于这个串的长度),之后直接主席树优化建图就好了

    之后就会收获(TLE)的好成绩

    显然我们并不需要那么麻烦,我们发现(SAM)(parent)是一个天然的树形结构,可以直接用来帮助我们优化建图

    于是我们可以直接在(SAM)上利用树上倍增直接定位好子串,对于每一个(A)串,向对应的(B)串连边就好了,边权就是(A)串的长度

    之后一波码码码就会发现过不了第三个样例,调一调发现有一些子串定位在一起了

    于是考虑我们舍弃后缀自动机的最小性,我们考虑对于每一个被定位了多次的位置拆出多个点来,毕竟(SAM)上一个节点代表的本来也就不是一个子串

    之后按照上面的方式建图跑一波拓扑排序就够了

    代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<set>
    #define re register
    #define mp std::make_pair
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=4e5+16;
    typedef std::pair<int,int> pii;
    std::set<pii> s;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    struct E{int v,nxt,w;}e[maxn<<1];
    int T,n,m,lst,cnt,num,K,tmp;
    char S[maxn>>1];
    int pos[maxn>>1];
    int l[maxn],r[maxn],p[maxn],deep[maxn],lg[maxn>>1],g[maxn];
    int len[maxn],son[maxn][26],fa[maxn],A[maxn],f[maxn][20],head[maxn<<1];
    int c[maxn<<1],tax[maxn>>1],q[maxn<<1],a[maxn<<1];
    std::vector<pii> d[maxn];
    std::vector<int> v[maxn];
    LL ans,dp[maxn<<1];
    inline void add(int x,int y,int w) {
    	e[++num].v=y;e[num].nxt=head[x];
    	head[x]=num;c[y]++;e[num].w=w;
    }
    inline void ins(int c,int o) {
    	int p=++cnt,f=lst;lst=p;
    	len[p]=len[f]+1,pos[o]=p;
    	while(f&&!son[f][c]) son[f][c]=p,f=fa[f];
    	if(!f) {fa[p]=1;return;}
    	int x=son[f][c];
    	if(len[x]==len[f]+1) {fa[p]=x;return;}
    	int y=++cnt;
    	len[y]=len[f]+1,fa[y]=fa[x],fa[p]=fa[x]=y;
    	for(re int i=0;i<26;i++) son[y][i]=son[x][i];
    	while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];
    }
    inline void Pre(int L) {
    	for(re int i=1;i<=cnt;i++) tax[len[i]]++;
    	for(re int i=1;i<=L;i++) tax[i]+=tax[i-1];
    	for(re int i=cnt;i;--i) A[tax[len[i]]--]=i;
    	for(re int i=1;i<=cnt;i++) {
    		int x=A[i];
    		deep[x]=deep[fa[x]]+1;
    		v[fa[x]].push_back(x);
    	}
    	for(re int i=1;i<=L;i++) tax[i]=0;
    }
    inline int jump(int x,int l) {
    	for(re int j=lg[deep[x]];j>=0;--j) 
    	if(len[f[x][j]]>=l) x=f[x][j];
    	pii t=mp(x,l);
    	if(s.find(t)==s.end()) g[x]++,s.insert(t);
    	return x;
    }
    void dfs(int x,int fa) {
    	if(fa) add(fa,x,0);
    	int h=0;
    	std::sort(d[x].begin(),d[x].end());
    	if(d[x].size()) {
    		p[d[x][0].second]=x;
    		for(re int i=1;i<d[x].size();i++) {
    			if(d[x][i].first!=d[x][i-1].first) {h=i;break;}
    			p[d[x][i].second]=x;
    		}
    	}
    	int pre=x;
    	while(g[x]>1) {
    		++cnt;g[x]--;
    		p[d[x][h].second]=cnt;
    		for(re int i=h+1;i<d[x].size();i++) {
    			if(d[x][i].first!=d[x][i-1].first) {h=i;break;}
    			p[d[x][i].second]=cnt;
    		}
    		add(pre,cnt,0);pre=cnt;
    	}
    	for(re int i=0;i<v[x].size();i++) dfs(v[x][i],pre);
    }
    int main() {
    	T=read();
    	lg[1]=1;//倍增不加1,爆零两行泪。
    	for(re int i=2;i<=200005;i++) lg[i]=lg[i>>1]+1;
    	while(T--) {
    		s.clear();
    		for(re int i=1;i<=cnt;i++) deep[i]=head[i]=c[i]=a[i]=dp[i]=0;
    		for(re int i=1;i<=tmp;i++) v[i].clear(),d[i].clear();
    		for(re int i=1;i<=tmp;i++) memset(son[i],0,sizeof(son[i])),fa[i]=0,g[i]=0;
    		num=0;lst=cnt=1;
    		scanf("%s",S+1);int L=strlen(S+1);
    		for(re int i=L;i;--i) ins(S[i]-'a',i);
    		Pre(L);
    		for(re int i=2;i<=cnt;i++) 
    			f[i][0]=fa[i];
    		for(re int j=1;j<=lg[L];j++)
    			for(re int i=2;i<=cnt;i++) 
    				f[i][j]=f[f[i][j-1]][j-1];
    		n=read();
    		for(re int i=1;i<=n;i++) 
    			l[i]=read(),r[i]=read(),p[i]=jump(pos[l[i]],r[i]-l[i]+1);
    		m=read();
    		for(re int i=n+1;i<=n+m;i++) 
    			l[i]=read(),r[i]=read(),p[i]=jump(pos[l[i]],r[i]-l[i]+1);
    		for(re int i=1;i<=n+m;i++) 
    			d[p[i]].push_back(mp(r[i]-l[i]+1,i));
    		tmp=cnt;
    		dfs(1,0);
    		for(re int i=1;i<=n;i++) a[p[i]]=r[i]-l[i]+1;
    		K=read();
    		for(re int x,y,i=1;i<=K;i++) {
    			x=read(),y=read();
    			add(p[x],p[y+n],r[x]-l[x]+1);
    		}
    		int tot=0;ans=0;
    		q[++tot]=1;
    		for(re int i=1;i<=tot;i++) {
    			int x=q[i];
    			ans=max(ans,dp[x]+a[x]);
    			for(re int j=head[x];j;j=e[j].nxt) {
    				c[e[j].v]--;
    				dp[e[j].v]=max(dp[e[j].v],dp[x]+e[j].w);
    				if(!c[e[j].v]) q[++tot]=e[j].v;
    			}
    		} 
    		if(tot<cnt) puts("-1");
    		else printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    存储过程编译出现锁死情况的解决方法
    国庆带你回家
    端午假期·广州之旅
    造成开发效率底下并且代码难以维护的 35 个恶习
    Linux下mysql自动备份脚本
    在咸阳机场等候登机有感
    vant3图片二进制上传
    浅谈前端缓存(转至大佬)
    vue3中使用$nextTick
    调取接口分页
  • 原文地址:https://www.cnblogs.com/asuldb/p/10670230.html
Copyright © 2020-2023  润新知