2014西安网络预选赛1002(后缀数组求第K大的子串)hdu5008

Boring String Problem

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 272    Accepted Submission(s): 65


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 s i...j of the string s = a 1a 2 ...a n(1 ≤ i ≤ j ≤ n) is the string a ia i+1 ...a j. Two substrings s x...y and s z...w are cosidered to be distinct if s x...y ≠ S z...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| ≤ 10 5) with only lowercase letters.

Next line contains a postive integer q(1 ≤ q ≤ 10 5), 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 < 2 63, “⊕” 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 s l...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 s 1...n is the whole string)
 

Sample Input
 
    
aaa 4 0 2 3 5
 

Sample Output
 
    
1 1 1 3 1 2 0 0

题意:找出第k大的子串,有多种情况要取l最小的一个

思路:比赛的时候看完题目以后大概知道是后缀数组,就没细想了,因为还有其它过的人更多的题没做出来= =

            首先注意后缀数组可以求出到第i个后缀一共有多少种不同的子串

            先不考虑前面的影响,而第i个后缀不同的子串的个数就等于在该后缀上找前缀的个数,就等于该后缀的长度,即cnt=n-sa[i]

            而这个cnt是包含了与上一个名次的后缀前面一样的串的个数,所以还要减去这部分(恰好等于height[i]),即cnt=cnt - height[i]

            然后对于查询,只需要二分找到第一个满足的sa[i],那么就可以从sa[i]开始往后枚举最小的下标,因为后面可能存在一样的串且下标更小

#include 
#include 
#include 
#include 
#include 
using namespace std;
#define maxn 100010
typedef __int64 ll;
char s[maxn];
int ra[maxn];
int t2[maxn];
int c[maxn];
int sa[maxn];
int height[maxn];

void build_sa(int m,int n)
{
    int *x=ra,*y=t2,k,i;
    for(i=0;i=0;i--)sa[--c[x[i]]]=i;

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

        for(i=0;i=0;i--)sa[--c[x[y[i]]]]=y[i];
        int *tt=x;x=y;y=tt;
        p=1;x[sa[0]]=0;
        for(i=1;i=n)break;
        m=p;
    }
}

void getheight(int n)
{
    int i,k=0;
    for(i=0;i solve(ll k,int n)
{
    vectorq(2,0);
    if(k>kth[n])return q;
    int l=1,r=n;

    while(l<=r)
    {
        int m=l+r>>1;

        if(k<=kth[m])
        {
            r=m-1;
        }
        else {
            l=m+1;
        }
    }

    --l;

    k-=kth[l];

    int len=height[l+1]+k;
    q[0]=sa[l+1]+1;
    q[1]=sa[l+1]+len;

    for(int i=l+2;i<=n;i++)
    {
        if(height[i]>=len)
        {
            if(q[0]>sa[i]+1)
            {

            q[0]=sa[i]+1;
            q[1]=sa[i]+len;

            }
        }
        else break;
    }

    return q;
}

int main()
{
    while(scanf("%s",s)!=EOF)
    {
        int n=strlen(s);

        s[n]='0';

        build_sa(200,n+1);
        getheight(n+1);
        getkth(n);

        int Q;

        scanf("%d",&Q);

        int l=0,r=0;

        for(int i=0;iq(2,0);
            q=solve(k,n);

            printf("%d %d\n",q[0],q[1]);

            l=q[0];
            r=q[1];
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构_后缀数组)