Boring String Problem

版权声明:小白一个,欢迎各位指错。 https://blog.csdn.net/qq_36424540/article/details/82533445

Problem Description

In this problem, you are given a string s and q queries.

For each query, you should answer that when all distinct substrings of string s were sorted lexicographically, which one is the k-th smallest.

A substring si...j of the string s = a1a2 ...an(1 ≤ i ≤ j ≤ n) is the string aiai+1 ...aj. Two substrings sx...y and sz...w are cosidered to be distinct if sx...y ≠ Sz...w

Input

The input consists of multiple test cases.Please process till EOF.

Each test case begins with a line containing a string s(|s| ≤ 105) with only lowercase letters.

Next line contains a postive integer q(1 ≤ q ≤ 105), the number of questions.

q queries are given in the next q lines. Every line contains an integer v. You should calculate the k by k = (l⊕r⊕v)+1(l, r is the output of previous question, at the beginning of each case l = r = 0, 0 < k < 263, “⊕” denotes exclusive or)

Output

For each test case, output consists of q lines, the i-th line contains two integers l, r which is the answer to the i-th query. (The answer l,r satisfies that sl...r is the k-th smallest and if there are several l,r available, ouput l,r which with the smallest l. If there is no l,r satisfied, output “0 0”. Note that s1...n is the whole string)

Sample Input

aaa 4 0 2 3 5

Sample Output

扫描二维码关注公众号,回复: 3132415 查看本文章

1 1 1 3 1 2 0 0

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=b-1;i>=a;--i)

const int N=1e5+10;

char s[N];
int sa[N],t[N],t2[N],c[N];
void build_sa(int n,int m){
	int *x=t,*y=t2;
	rep(i,0,m)c[i]=0;
	rep(i,0,n)c[x[i]=s[i]]++;
	rep(i,1,m)c[i]+=c[i-1];
	per(i,0,n)sa[--c[x[i]]]=i;

	for(int k=1;k<=n;k<<=1){
		int p=0;
		rep(i,n-k,n)y[p++]=i;
		rep(i,0,n)if(sa[i]>=k)y[p++]=sa[i]-k;

		rep(i,0,m)c[i]=0;
		rep(i,0,n)c[x[y[i]]]++;
		rep(i,0,m)c[i]+=c[i-1];
		per(i,0,n)sa[--c[x[y[i]]]]=y[i];

		swap(x,y);
		p=1;x[sa[0]]=0;
		rep(i,1,n)x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
		if(p>=n)break;
		m=p;
	}
}

int rk[N],height[N];
void getHeight(int n){
	int k=0;
	rep(i,0,n)rk[sa[i]]=i;
	rep(i,0,n){
		if(k)k--;
		int j=sa[rk[i]-1];//注意不要有rk[i]=0,所以我们通常在末尾添加一个 最小值,让他把0拿走 
		while(s[i+k]==s[j+k])k++;
		height[rk[i]]=k;
	}
}
LL sum[N];

int len;
void get_ans(LL& l,LL& r,LL K){
	if(K>sum[len]){
		l=r=0;
		return;
	}
	int pos=lower_bound(sum,sum+len+1,K)-sum;

	K-=sum[pos-1];

	l=sa[pos];
	r =sa[pos]+height[pos]+K;

	int tlen=r-l;
	pos++;
	while(pos<=len&&height[pos]>=tlen){
		if(sa[pos]<l){
			l=sa[pos];
			r=l+tlen;
		}
		pos++;
	}
	l++,r;
}

int main(){
	while(scanf("%s",s)==1){
		len=strlen(s);
		s[len]=0;

		build_sa(len+1,200);
		getHeight(len+1);
		
		//pos=0的位置的字符,属于添加,不计算 
		rep(i,1,len+1)sum[i]=sum[i-1]+len-sa[i]-height[i];

		int m;
		scanf("%d",&m);
		LL l=0,r=0;
		while(m--){
			LL K;
			scanf("%lld",&K);
			K=(l^r^K)+1LL;
		//	printf("l:%lld r:%lld KKK:%lld\n",l,r,K);
			get_ans(l,r,K);
			printf("%lld %lld\n",l,r);
		}
	}
	return 0;
}

RMQ+二分

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i=a;i<b;++i)
#define per(i,a,b) for(int i=b-1;i>=a;--i)

//后缀数组
//begin
//sa[i] 排名第i的为 S[sa[i]---len)这个后缀, sa[]从0开始,一般我们添加 极小字符,使略过0,从1开始
//height[i] 为 sa[i]和sa[i-1]的LCP 

//rk[i] 为 下标为i的字符串的实际rank 
const int N=1e5+10;
int r[N];//需先将字符串 转换成 int 类型;末尾添加最小字符
int sa[N],t[N],t2[N],c[N]; 
void build_sa(int n,int m){
	int *x=t,*y=t2;
	rep(i,0,m)c[i]=0;
	rep(i,0,n)c[x[i]=r[i]]++;
	rep(i,1,m)c[i]+=c[i-1];
	per(i,0,n)sa[--c[x[i]]]=i;

	for(int k=1;k<=n;k<<=1){
		int p=0;
		rep(i,n-k,n)y[p++]=i;
		rep(i,0,n)if(sa[i]>=k)y[p++]=sa[i]-k;

		rep(i,0,m)c[i]=0;
		rep(i,0,n)c[x[y[i]]]++;
		rep(i,0,m)c[i]+=c[i-1];
		per(i,0,n)sa[--c[x[y[i]]]]=y[i];

		swap(x,y);
		p=1;x[sa[0]]=0;
		rep(i,1,n)x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
		if(p>=n)break;
		m=p;
	}
}
int rk[N],height[N];
void getHeight(int n){
	int k=0;  //跳过最小的 后面的添加字符 
	rep(i,0,n)rk[sa[i]]=i;
	rep(i,0,n-1){//最后的那个不要计算,否则RE 
		if(k)k--;
		int j=sa[rk[i]-1];//注意不要有rk[i]=0,所以我们通常在末尾添加一个 最小值,让他把0拿走
		while(r[i+k]==r[j+k])k++;
		height[rk[i]]=k;
	}
}

int Log[N];
int dp_heigh[N][20],dp_pos[N][20];//一个是位置,一个是区域最小值
void get_rmq(int n,int X[],int (*dp)[20]){
    rep(i,1,n)dp[i][0]=X[i];//初始化每个点
    for(int j=1;j<=Log[n];++j){
        for(int i=1;i+(1LL<<j)-1<n;++i){
            dp[i][j]=min(dp[i][j-1],dp[i+(1LL<<(j-1))][j-1]);
        }
    }
}
int RMQ(int (*dp)[20],int L,int R){//返回区域内的最小值 ,pos,和 val
    if(L>R)swap(L,R);
    int tmp=Log[R-L+1];
    //printf("L:%d R:%d tmp:%d\n",L,R-(1LL<<tmp)+1,tmp);
    return min(dp[L][tmp],dp[R-(1LL<<tmp)+1][tmp]);
}
//end


LL sum[N];
int len;
//枚举的效率,很低,我们可以rmq找到 一段区间内 都是>=Len的位置。
void get_ans(LL& L,LL& R,LL K){
	if(K>sum[len]){L=R=0;return;}
	
	int pos=lower_bound(sum,sum+len+1,K)-sum;
	K-=sum[pos-1];

	L=sa[pos];//我们找到了按照 后缀排序的最前面的值,但不一定是 物理上最左面的值
	R=sa[pos]+height[pos]+K-1;
    int tlen=R-L+1;
    
    int Max_Rig=pos;
    int l=pos+1,r=len,mid;
    while(l<=r){
        mid=(l+r)>>1;
        if(RMQ(dp_heigh,pos+1,mid)>=tlen){
            Max_Rig=mid; l=mid+1;
        }
        else
            r=mid-1;
    }
    L=RMQ(dp_pos,pos,Max_Rig);
    R=L+tlen;
    ++L;
}

char s[N];
int main(){

    Log[1]=0;
    rep(i,2,N)Log[i]=Log[i/2]+1;

	while(scanf("%s",s)==1){
		len=strlen(s);

		rep(i,0,len)r[i]=s[i]-'a'+1;
		r[len]=0;//在末尾添加一个 最小的字符,日常操作(防止get_height里面RE)

		build_sa(len+1,27);
		getHeight(len+1);

        get_rmq(len+1,height,dp_heigh);
        get_rmq(len+1,sa,dp_pos);

		//排名第一 的位置的字符,属于添加,不计算
		rep(i,1,len+1)sum[i]=sum[i-1]+len-sa[i]-height[i];
        
		int m;
		scanf("%d",&m);
		LL l=0,r=0;
		while(m--){
			LL K;
			scanf("%lld",&K);
			K=(l^r^K)+1LL;
			get_ans(l,r,K);
			printf("%lld %lld\n",l,r);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36424540/article/details/82533445