【题目大意】
有一个字符串,将它的所有非空子串去重后排序,求排序第k大的字串位置,如果有多个,输出最前面的位置。
【思路】
按后缀排序后,所有子串就是这些后缀的前缀。排名为i的后缀,会有n - sa[i]个前缀,并且,他们的字典大小是按长度排序的。对于后缀i-1和后缀i,后缀会出现heigt[i]个重复串,哪些不重复的串,任意一个都比以前出现的串,字典序更大。那么,使用二分,就可以找到第k的串的一个位置。
剩下的问题,就是怎么去找到位置最前面的串。因为后缀数组的固有性质(相似度越高的,就越在一起),我们可以利用二分,找到一个连续区间,这个区间的每个后缀和找到的那个解的公共前缀包括原来的那个解。之后,就是找这个区间,哪个串是最先出现的(这可以用rmq搞定)。
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<cctype>
#include<string>
#include<algorithm>
#include<iostream>
#include<ctime>
#include<map>
#include<set>
using namespace std;
#define MP(x,y) make_pair((x),(y))
#define PB(x) push_back(x)
typedef __int64 LL;
//typedef unsigned __int64 ULL;
/* ****************** */
const int INF = 1000111222;
const double INFF = 1e100;
const double eps = 1e-8;
const int mod = 1000000007;
const int NN = 100009;
const int MM = 400010;
/* ****************** */
int a[NN];
char ss[NN];
int wa[NN],wb[NN],wv[NN],wss[NN],sa[NN];
int rank[NN],height[NN];
int rmq[NN][20],long2[NN];
int rmq1[NN][20];
LL sum[NN];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int n,int m)
{
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++)wss[i]=0;
for(i=0;i<n;i++)wss[x[i]=r[i]]++;
for(i=1;i<m;i++)wss[i]+=wss[i-1];
for(i=n-1;i>=0;i--)sa[--wss[x[i]]]=i;
for(j=1,p=1;p<n;j*=2,m=p)
{
for(p=0,i=n-j;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
for(i=0;i<n;i++)wv[i]=x[y[i]];
for(i=0;i<m;i++)wss[i]=0;
for(i=0;i<n;i++)wss[wv[i]]++;
for(i=1;i<m;i++)wss[i]+=wss[i-1];
for(i=n-1;i>=0;i--)sa[--wss[wv[i]]]=y[i];
for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
return;
}
void calheight(int *r,int n)
{
int i,j,k=0;
for(i=1;i<=n;i++)rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
void initRMQ(int n)
{
int i,j,en;
long2[1]=0;
for(i=2;i<=n;i++)
{
long2[i]=long2[i-1]+(i==(i&(-i)));
}
for(i=1;i<=n;i++)rmq[i][0]=height[i];
for(j=1;j<=long2[n];j++)
{
en=n+1-(1<<j);
for(i=1;i<=en;i++)
rmq[i][j]=min(rmq[i][j-1],rmq[ i+(1<<(j-1)) ][j-1]);
}
}
int lcp(int i,int j,int n)
{
// i=rank[i],j=rank[j];
if(i==j)return n - sa[i];
if(i>j)swap(i,j);
i++;
int k=long2[j-i+1];
int ans=min(rmq[i][k],rmq[ j+1-(1<<k) ][k]);
return ans;
}
void init(int n)
{
int i, j, en;
for (i = 1; i <= n; i ++)
rmq1[i][0] = sa[i];
for (j = 1; j <= long2[n]; j ++)
{
en = n + 1 - (1<<j);
for (i = 1; i <= en; i ++)
rmq1[i][j] = min(rmq1[i][j-1], rmq1[i+(1<<(j-1))][j-1]);
}
}
int GET_MIN(int st,int en)
{
int k = long2[en-st+1];
return min(rmq1[st][k], rmq1[ en+1-(1<<k) ][k]);
}
void goo(LL &st,LL &en,int n)
{
LL l, r, mid, len = en - st + 1;
int k = rank[st];
// printf("k==%d\n",k);
l = 1;
r = k;
while (l < r)
{
mid = (l + r) >> 1;
if(lcp(mid, k, n) >= len)
r = mid;
else
l = mid + 1;
}
st = l;
// cout<<"st=="<<st<<endl;
l = k;
r = n;
while (l < r)
{
mid = (l + r + 1) >> 1;
if (lcp(mid, k, n) >= len)
l = mid;
else
r = mid - 1;
}
en = l;
// cout<<"en=="<<en<<endl;
st = GET_MIN(st, en);
en = st + len;
st ++;
printf("%I64d %I64d\n",st,en);
}
void fun(LL &st,LL &en,LL k,int n)
{
if(k > sum[n])
{
st = en = 0;
puts("0 0");
return;
}
int l;
l = lower_bound(sum+1, sum+1+n, k) - sum;
k -= sum[l-1];
st = sa[l];
en = sa[l] + height[l] + k - 1;
// printf("[] == %I64d %I64d\n",st+1,en+1);
goo(st, en, n);
}
void solve(int n,int m)
{
LL l, r, t, k;
l = r = 0;
while (m--)
{
scanf("%I64d", &t);
k = (l^r^t) + 1;
fun(l, r, k, n);
}
}
int main()
{
int i, n, m;
while (scanf("%s", ss) != EOF)
{
n = strlen(ss);
for (i = 0; i < n; i ++)
{
a[i] = ss[i] - 'a' + 1;
}
a[n] = 0;
da(a, n+1, 30);
calheight(a, n);
initRMQ(n);
init(n);
sum[0] = 0;
for (i = 1; i <= n; i ++)
{
sum[i] = n - sa[i] - height[i];
sum[i] += sum[i-1];
}
scanf("%d", &m);
solve(n, m);
}
return 0;
}