• 【[HEOI2016/TJOI2016]字符串】


    码农题啊

    上来先无脑一个(SA)的板子,求出(SA)(het)数组

    我们只需要从(sa[i]in[a,b])的所有(i)中找到一个(i)使得(sa[i])(rk[c])之间的最小值最大就好了

    但是还必须得满足(sa[i]+lcp-1<=b),毕竟整个串还得在([a,b])内部

    考虑一下二分答案

    根据(het)数组的性质显然越靠近(rk[c])(sa[i])形成的(lcp)越长,于是我们可以利用一个(ST)表加二分找到从(rk[i])往前开始的一个尽量长的区间整个区间内的所有(het)大于等于当前二分出来的(mid)

    之后查一下这个区间内部有多少个在([a,b-mid+1])范围的(sa),这样如果存在任意一个数,就会满足条件

    可以用主席树来做到这一点

    代码

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define re register
    #define LL long long
    #define maxn 100005
    #define M 5000005
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    inline int read()
    {
    	re char c=getchar();int x=0;
    	while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int n,m,Q,cnt;
    char S[maxn];
    int rk[maxn],het[maxn],sa[maxn],tax[maxn],tp[maxn],rt[maxn],log_2[maxn];
    int St[maxn][18];
    int ls[M],rs[M],d[M];
    int change(int pre,int x,int y,int pos)
    {
    	int root=++cnt;
    	d[root]=d[pre]+1;
    	if(x==y) return root;
    	ls[root]=ls[pre],rs[root]=rs[pre];
    	int mid=x+y>>1;
    	if(pos<=mid) ls[root]=change(ls[pre],x,mid,pos);
    		else rs[root]=change(rs[pre],mid+1,y,pos);
    	return root;
    }
    inline void qsort()
    {
    	for(re int i=0;i<=m;i++) tax[i]=0;
    	for(re int i=1;i<=n;i++) tax[rk[i]]++;
    	for(re int i=1;i<=m;i++) tax[i]+=tax[i-1];
    	for(re int i=n;i;--i) sa[tax[rk[tp[i]]]--]=tp[i];
    }
    inline int ask(int l,int r)
    {
    	int k=log_2[r-l+1];
    	return min(St[l][k],St[r-(1<<k)+1][k]);
    }
    int query(int p1,int p2,int pos,int x,int y)
    {
    	if(x==y) return d[p2]-d[p1];
    	int mid=x+y>>1;
    	if(pos<=mid) return query(ls[p1],ls[p2],pos,x,mid);
    		return d[ls[p2]]-d[ls[p1]]+query(rs[p1],rs[p2],pos,mid+1,y);
    }
    inline int check(int now,int l,int r,int pos)
    {
    	int L=1,R=pos,to=0;
    	while(L<=R)
    	{
    		int mid=L+R>>1;
    		if(ask(mid,pos)>=now) R=mid-1,to=mid;
    			else L=mid+1;
    	}
    	if(to&&query(rt[to-2],rt[pos],r-now+1,1,n)-((l-1)?(query(rt[to-2],rt[pos],l-1,1,n)):0)) return 1; 
    	L=pos+1,R=n,to=0;
    	while(L<=R)
    	{
    		int mid=L+R>>1;
    		if(ask(pos+1,mid)>=now) L=mid+1,to=mid;
    			else R=mid-1;
    	}
    	if(to&&query(rt[pos-1],rt[to],r-now+1,1,n)-((l-1)?(query(rt[pos-1],rt[to],l-1,1,n)):0)) return 1;
    	return 0;
    }
    int main()
    {
    	n=read(),Q=read(),scanf("%s",S+1);
    	m=75;
    	for(re int i=1;i<=n;i++) 
    		rk[i]=S[i]-'a'+1,tp[i]=i;
    	qsort();
    	for(re int w=1,p=0;p<n;m=p,w<<=1)
    	{
    		p=0;
    		for(re int i=1;i<=w;i++) tp[++p]=n-w+i;
    		for(re int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
    		qsort();
    		for(re int i=1;i<=n;i++) std::swap(rk[i],tp[i]);
    		rk[sa[1]]=p=1;
    		for(re int i=2;i<=n;i++) rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
    	}
    	int k=0;
    	for(re int i=1;i<=n;i++)
    	{
    		if(k) --k;
    		int j=sa[rk[i]-1];
    		while(S[i+k]==S[j+k]) ++k;
    		het[rk[i]]=k;
    	}
    	memset(St,20,sizeof(St));
    	int num=0;
    	for(re int i=2;i<=n;i++) log_2[i]=1+log_2[i/2];
    	for(re int i=1;i<=n;i++) St[i][0]=het[i];
    	for(re int j=1;j<=log_2[n];j++)
    		for(re int i=1;i+(1<<j)-1<=n;i++) St[i][j]=min(St[i][j-1],St[i+(1<<(j-1))][j-1]);
    	for(re int i=1;i<=n;i++)
    		rt[i]=change(rt[i-1],1,n,sa[i]);
    	while(Q--)
    	{
    		int x=read(),y=read(),xx=read(),yy=read();
    		int R=y-x+1,L=1,ans=0;
    		while(L<=R)
    		{
    			int mid=L+R>>1;
    			if(check(mid,x,y,rk[xx])) L=mid+1,ans=mid;
    				else R=mid-1;
    		}
    		ans=min(ans,yy-xx+1);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    使用QOAuth来进行新浪/腾讯微博验证(二)
    很不错的Utility库,C#4扩展 各种功能齐全,两行代码搞定图片转字符
    使用QOAuth来进行新浪/腾讯微博验证(一)
    可怜的小猪&香农熵
    消息队列MQ如何保证消息不丢失
    40 亿个 QQ 号码如何去重,bitmap去重
    参数的设置
    自动化测试的十个要点
    LR学习中的一个低级错误
    Windows下用CMake编译libuv
  • 原文地址:https://www.cnblogs.com/asuldb/p/10205627.html
Copyright © 2020-2023  润新知