• YbtOJ相似子串【SA,RMQ,二分】


    正题


    题目大意

    给出一个长度为\(n\)的字符串,两个串相似当且仅当可以通过每种字符置换使得它们相同。

    \(q\)次询问这个字符串所有子串中和这个串中\(s_{l,r}\)子串有多少个相似的。

    \(1\leq n\leq 10^5,1\leq q\leq 5\times 10^5\)

    字符集是数字\(0\sim 9\)


    解题思路

    请问我是在阴间吗
    请添加图片描述
    首先对于相似的比较相信很常见,维护每个数字上一个和它相同的数字的距离,然后没有上一个就定为\(0\)就好了。

    但是这题的问题在于我们提取出区间构成的数组时前面有些要变成\(0\)

    同样的这也是个提示,因为字符集大小只有10,我们也可以从这里入手,对于一个后缀,我们把第一个出现的数字的位置挖空后,我们至多会把这个后缀以这些位置分成\(10\)份,我们将这个字符串序列称之为这个后缀的值。

    然后我们需要的就是这些后缀值的“LCP”,而这样我们需要我们能快速求这些后缀中字符串的LCP。

    子串的LCP直接上SA+RMQ就好了。

    这样我们把弄出来的后缀的值排好序,然后维护一个相邻的两两之间的"LCP"计入一个类似height的数组的东西。

    然后对于询问我们就直接二分在RMQ上查询就好了。

    时间复杂度:\(O(10n\log n+q\log n)\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int N=1e5+10;
    struct node{
    	int l,r;
    };
    struct nstr{
    	vector<node> r;
    	int id;
    }sr[N];
    int n,m,q,nxt[10],p[10],pos[N];
    int x[N],y[N],c[N],sa[N],rk[N];
    int lg[N],f[N][20],h[N],s[N];
    char rs[N];
    void Qsort(){
    	for(int i=1;i<=m;i++)c[i]=0;
    	for(int i=1;i<=n;i++)c[x[i]]++;
    	for(int i=1;i<=m;i++)c[i]+=c[i-1];
    	for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
    	return;
    }
    void Get_SA(){
    	for(int i=1;i<=n;i++)
    		x[i]=s[i]+1,m=max(m,s[i]+1),y[i]=i;
    	Qsort();
    	for(int w=1;w<=n;w<<=1){
    		int p=0;
    		for(int i=n-w+1;i<=n;i++)y[++p]=i;
    		for(int i=1;i<=n;i++)
    			if(sa[i]>w)y[++p]=sa[i]-w;
    		Qsort();swap(x,y);x[sa[1]]=p=1;
    		for(int i=2;i<=n;i++)
    			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+w]==y[sa[i-1]+w])?p:(++p);
    		if(p==n)break;m=p;
    	}
    	return;
    }
    void Get_Height(){
    	int k=0;
    	for(int i=1;i<=n;i++)rk[sa[i]]=i;
    	for(int i=1;i<=n;i++){
    		if(rk[i]==1)continue;
    		if(k)k--;int j=sa[rk[i]-1];
    		while(i+k<=n&&j+k<=n&&s[j+k]==s[i+k])k++;
    		h[rk[i]]=f[rk[i]][0]=k;
    	}
    	return;
    }
    void Get_RMQ(){
    	for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
    	for(int j=1;(1<<j)<=n;j++)
    		for(int i=1;i+(1<<j)-1<=n;i++)
    			f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
    	return;
    }
    int RMQ(int l,int r){
    	if(!l||!r)return 0;
    	if(l==r)return n-l+1;
    	l=rk[l];r=rk[r];
    	if(l>r)swap(l,r);l++;
    	int z=lg[r-l+1];
    	return min(f[l][z],f[r-(1<<z)+1][z]);
    }
    int RMQs(int l,int r){
    	l++;int z=lg[r-l+1];
    	return min(f[l][z],f[r-(1<<z)+1][z]);
    }
    void SA(){
    	Get_SA();
    	Get_Height();
    	Get_RMQ();
    	return;
    }
    int cp(node x,node y){//x<=y
    	if(!x.l&&!y.l)return 2;
    	if(!x.l)return 1;
    	if(!y.l)return 0;
    	int len=RMQ(x.l,y.l);
    	if(len>x.r-x.l||len>y.r-y.l){
    		if(x.r-x.l==y.r-y.l)return 2;
    		return (x.r-x.l)<(y.r-y.l);
    	}
    	return s[x.l+len]<s[y.l+len];
    }
    bool cmp(nstr x,nstr y){
    	int i=0;
    	while(1){
    		if(i>=x.r.size())return 0;
    		if(i>=y.r.size())return 1;
    		int op=cp(x.r[i],y.r[i]);
    		if(op==2)i++;
    		else return op;
    	}
    	return 0;
    }
    int LCP(nstr x,nstr y){
    	int i=0,ans=0;
    	while(i<x.r.size()&&i<y.r.size()&&cp(x.r[i],y.r[i])==2)
    		ans+=x.r[i].r-x.r[i].l+1,i++;
    	if(i<x.r.size()&&i<y.r.size())ans+=min(RMQ(x.r[i].l,y.r[i].l),min(x.r[i].r-x.r[i].l,y.r[i].r-y.r[i].l)+1);
    	return ans;
    }
    int main()
    {
    //	freopen("similar.in","r",stdin);
    //	freopen("similar.out","w",stdout); 
    	scanf("%d%d",&n,&q);
    	scanf("%s",rs+1);
    	for(int i=1;i<=n;i++){
    		if(!nxt[rs[i]-'0'])s[i]=0;
    		else s[i]=i-nxt[rs[i]-'0'];
    		nxt[rs[i]-'0']=i;
    	}
    	SA();memset(nxt,0,sizeof(nxt));
    	for(int i=n;i>=1;i--){
    		nxt[rs[i]-'0']=i;
    		for(int j=0;j<=9;j++)p[j]=nxt[j];
    		sort(p,p+10);
    		int now=i;
    		for(int j=0;j<=9;j++){
    			if(!p[j])continue;
    			if(p[j]>now)
    				sr[i].r.push_back((node){now,p[j]-1});
    			sr[i].r.push_back((node){0,0});
    			now=p[j]+1;
    		}
    		if(now<=n)sr[i].r.push_back((node){now,n});
    		sr[i].id=i;
    	}
    	sort(sr+1,sr+1+n,cmp);
    	for(int i=1;i<=n;i++)
    		pos[sr[i].id]=i;
    	for(int i=2;i<=n;i++)h[i]=LCP(sr[i-1],sr[i]);
    	for(int i=2;i<=n;i++)f[i][0]=h[i];
    	for(int j=1;(1<<j)<=n;j++)
    		for(int i=1;i+(1<<j)-1<=n;i++)
    			f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
    	int las=0;
    	while(q--){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		l^=las;r^=las;
    		if(l>n||r>n||l<1||r<1)continue;
    		int x=pos[l],len=r-l+1;
    		int L=x+1,R=n,ans=1;
    		while(L<=R){
    			int mid=(L+R)>>1;
    			if(RMQs(x,mid)>=len)L=mid+1;
    			else R=mid-1;
    		}
    		ans+=R-x;L=1;R=x-1;
    		while(L<=R){
    			int mid=(L+R)>>1;
    			if(RMQs(mid,x)>=len)R=mid-1;
    			else L=mid+1;
    		}
    		ans+=x-L;
    		printf("%d\n",las=ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    C语言 unsigned 和 signed 类型相互转换深入理解
    C++的关键字 explicit的作用———菜鸟级日记
    solr笔记
    矩阵解
    USACO题目——Transformations
    模块化加载时断点调试没反应,进入不了断点
    flash中的渐变滤镜GradientGlowFilter
    Flash Builder 找不到所需的Adobe Flash Player调试器版本的解决办法
    使用Pixel Bender 和Shader Job来处理普通数据运算
    关于Event.ADDED_TO_STAGE
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15864835.html
Copyright © 2020-2023  润新知