題目大意:
給你一個S串,多次詢問第k大的不重複子串。
解題思路:
因爲之前做過一個重複子串的第k大,所以這個題做的比較輕鬆。畢竟我感覺那個題目比這個難得多。
首先用一個數組直接儲存1 到 i這個位置所有的不重複子串和。
查詢第k大的時候直接先二分找到我們所要找的子串的起始下標。知道起始下標之後相當於我們就知道了這個串。
這個時候因爲題目有要求串相同的時候保證l r儘可能的小,這裏我認爲應該需要一些數據結構,畢竟暴力掃的話感覺很耗時誒= =
我用的暴力寫的, 即從pos這個位置向前遍歷和向後遍歷。height始終大於當前查找串的話就不斷更新 l 的最小值,最後輸出答案即可。
剛開始long long 寫爲了int 結果T了,還以爲不能暴力,結果換了long long之後過了。。。
額,反正先寫暴力寫法吧= =
Ac代碼:
#include<bits/stdc++.h>
#define rank ra
using namespace std;
const int maxn=3e5+10;
const int INF=1e9+7;
typedef long long ll;
char s[maxn];
int n,m,sa[maxn],rank[maxn],height[maxn],pos[maxn];
int t1[maxn],t2[maxn],r[maxn],c[maxn];
ll sum[maxn]; //儲存不重複子串前綴和
bool cmp(int *r,int a,int b,int l)
{
return r[a]==r[b] && r[a+l]==r[b+l];
}
void da(int str[],int sa[],int rank[],int height[],int n,int m)
{
n++;
int i,j,p,*x=t1,*y=t2;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[i]=str[i]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(int j=1;j<=n;j<<=1)
{
p=0;
for(int i=n-j;i<n;i++) y[p++]=i;
for(int i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
for(int i=0;i<m;i++) c[i]=0;
for(int i=0;i<n;i++) c[x[y[i]]]++;
for(int i=1;i<m;i++) c[i]+=c[i-1];
for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1,x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
if(p>=n) break;
m=p;
}
int k=0;
n--;
for(int i=0;i<=n;i++) rank[sa[i]]=i;
for(int i=0;i<n;i++)
{
if(k) k--;
j=sa[rank[i]-1];
while(str[i+k]==str[j+k]) k++;
height[rank[i]]=k;
}
}
int main()
{
while(scanf(" %s",s)!=EOF)
{
int ls=strlen(s),len=0;
for(int i=0;i<ls;i++) r[len++]=s[i];
r[len]=0;n=len;
da(r,sa,rank,height,n,128);
for(int i=1;i<=n;i++) //計算前綴和
sum[i]=n-sa[i]-height[i]+sum[i-1];
scanf("%d",&m);
int l=0,r=0;
ll q=0;
while(m--)
{
scanf("%lld",&q);
q=(l^r^q)+1;
int pos=lower_bound(sum+1,sum+1+n,q)-sum; //二分找到位置
if(sum[n]<q)
{
l=0,r=0;
printf("0 0\n");
continue;
}
l=sa[pos]; //處理出l和長度
q-=sum[pos-1];
int gk=height[pos]+q;
for(int i=pos;i>=1;i--) //向前向後找最小
{
if(height[i]>=gk)
l=min(l,sa[i]);
else break;
}
for(int i=pos;i<n;i++)
{
if(height[i+1]>=gk)
l=min(l,sa[i+1]);
else break;
}
r=l+gk-1;
l++,r++; //輸出答案
printf("%d %d\n",l,r);
}
}
return 0;
}