HDU 5008 Boring String Problem

后缀数组+RMQ+二分

后缀数组二分确定第K不同子串的位置 , 二分LCP确定可选的区间范围 , RMQ求范围内最小的sa

Boring String Problem

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


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
 

Source
2014 ACM/ICPC Asia Regional Xi'an Online
 


#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define prt(k) cout<<#k" = "<<k<<endl;
const int N = 100010;
int sa[N], rank[N], rank2[N], h[N],c[N], *x, *y, ans[N];
typedef long long ll;
char str[N];

bool cmp(int* r, int a, int b, int l, int n)
{
    return r[a]==r[b] && a+l<n && b+l<n && r[a+l]==r[b+l];
}
void radix_sort(int n,int sz)
{
    for(int i=0; i<sz; i++) c[i]=0;
    for(int i=0; i<n; i++) c[x[y[i]]]++;
    for(int i=1; i<sz; i++) c[i]+=c[i-1];
    for(int i=n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i];
}
void get_sa(char c[],int n,int sz=128)
{
    x=rank,y=rank2;
    for(int i=0;i<n;i++) x[i]=c[i],y[i]=i;
    radix_sort(n,sz);
    for(int len=1;len<n;len<<=1)
    {
        int yid=0;
        for(int i=n-len;i<n;i++) y[yid++]=i;
        for(int i=0;i<n;i++) if(sa[i]>=len) y[yid++]=sa[i]-len;
        radix_sort(n,sz);
        swap(x,y);
        x[sa[0]]=yid=0;
        for(int i=1;i<n;i++)
        {
            x[sa[i]]=cmp(y,sa[i],sa[i-1],len,n) ? yid : ++yid;
        }
        sz=yid+1;
        if(sz>=n) break;
    }
    for(int i=0;i<n;i++) rank[i]=x[i];
}
void get_h(char str[],int n)
{
    int k=0; h[0]=0x3f3f3f3f;
    for(int i=0;i<n;i++)
    {
        if(rank[i]==0) continue;
        k=max(k-1,0);
        int j=sa[rank[i]-1];
        while(i+k<n && j+k<n && str[i+k]==str[j+k]) k++;
        h[rank[i]]=k;
    }
}
int dp[N][20];
int mmm[N][22];
void RMQ_init(int n)
{
    for(int i=0;i<n;i++) dp[i][0]=h[i], mmm[i][0]=sa[i];
    dp[0][0]=0x3f3f3f3f;
    for(int i=1;(1<<i)<=n;i++)
    {
        for(int j=0;j+(1<<i)-1<n; j++)
            dp[j][i]=min(dp[j][i-1], dp[j+(1<<(i-1))][i-1]),
            mmm[j][i]=min(mmm[j][i-1], mmm[j+(1<<(i-1))][i-1]);
    }
}
int LCP(int l,int r,int n)
{
    if(l==r) return n-sa[l];
    l++;
    if(l>r) swap(l,r);
    int k = 0;
    while(1<<(k+1) <= r-l+1) k++;
    return min(dp[l][k],dp[r-(1<<k)+1][k]);
}
ll Range[N];
int bin(ll x, int n)
{
    int ans = -1;
    int l=0, r=n-1, mid;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(Range[mid]<x) ans=mid,l=mid+1;
        else r=mid-1;
    }
    return ans;
}
int MMM(int l, int r)
{
    if(l>r) swap(l,r);
    int k = 0;
    while(1<<(k+1) <= r-l+1) k++;
    return min(mmm[l][k], mmm[r-(1<<k)+1][k]);
}
int binID(int x,int n,int len)
{
    int ans=x;
    int l=x,r=n-1,mid;
    while(l<=r)
    {
        mid=(l+r)/2;
        if(LCP(x,mid,n)>=len)
        {
            ans=mid;
            l=mid+1;
        }
        else r=mid-1;
    }
    return ans;
}
int main()
{
while(scanf("%s",str)==1)
{
    int n=strlen(str);
    get_sa(str,n);
    get_h(str,n);
    RMQ_init(n);
    h[0]=0;
    for(int i=0;i<n;i++)
    {
        Range[i] = (n-sa[i])-h[i];
        if(i-1>=0) Range[i]+=Range[i-1];
    }
    int q; cin>>q;
    int L=0,R=0;
    while(q--)
    {
        ll V; scanf("%I64d",&V);
        ll K = (L^R^V) + 1;
        if(K>Range[n-1])
        {
            L=0, R=0;
            printf("0 0\n");
            continue;
        }
        int id = bin(K,n);
        ll jian=0;
        if(id>=0) jian=Range[id];
        ll res=K-jian;
        id++;
        int len=h[id]+res;
        int hid=binID(id,n,len);
        int Left=MMM(id,hid);
        L=Left+1, R=Left+len;
        printf("%d %d\n",L,R);
    }
}
}


你可能感兴趣的:(HDU 5008 Boring String Problem)