hdu 5008(2014 ACM/ICPC Asia Regional Xi'an Online ) Boring String Problem(后缀数组&二分)

Boring String Problem

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 219    Accepted Submission(s): 45

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

1 1
1 3
1 2
0 0

Source

2014 ACM/ICPC Asia Regional Xi‘an Online

Recommend

hujie   |   We have carefully selected several similar problems for you:  5017 5016 5015 5014 5013

题意:

给你一个长度不超过1e5的字符串。把它的所有子串去重后排序。然后要你输出第k大的字符串的位置l,r。如果有多个位置输出l最小的。

思路:

比赛时看到这题感觉和SPOJ-7258 Lexicographical
Substring Search
很像。

不过那是学后缀自动机时看到了。由于后缀自动机是在是不是很好懂。。。所以最后还是放弃了。但是网上有这题的题解。但是很那题有点差别的是这题要求输出字符串的位置。于是就不知道怎么搞了。于是就用相对熟悉的后缀数组想了下。毕竟这题感觉n*log(n)是可过的。然后就开干了。我们先算出来每个后缀sa[i]比sa[i-1]多出多少个不同的子串。明显为len-sa[i]-height[i]存到val[i]。而sa[i]就对应len-sa[i]-height[i]个子串了。然后用val[i]构造线段树。然后找排名第k的字符串怎么找呢。就类似二分的思想了。如果线段树左子树字符大于等于k个就到左子树。不行就到右子树找。这样就可以找到第k大串对应的sa[i]和第k串的长度len。写完这里就卡了下。因为怎么处理l最小的问题呢。不可能在i附近找和sa[i]lcp>=len且sa[i]最小的吧。想了下最发杂的就是全a的情况。这样就退化成O(n^2)了。那sa就白写了。

冷静了下。一想。就出来了。我们可以二分求出最左边和sa[i]lcp>=len的位置left。在二分出sa[i]最右边lcp>=len的位置right。然后答案就是left->right中sa最小的。这个可以用rmq维护。然后接1A了。不过有人就是按我先前的前后直接找的。居然过了。可见数据还是蛮水的。

详细见代码:

#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=100010;
typedef long long ll;
#define lson L,mid,ls
#define rson mid+1,R,rs
char txt[maxn];
int sa[maxn],T1[maxn],T2[maxn],ct[maxn],he[maxn],rk[maxn],n,m,le,ri;
int rmq[25][maxn],lg[maxn],id[25][maxn],pos,len;
ll num[maxn<<2];
void build(int L,int R,int rt)
{
    if(L==R)
    {
        num[rt]=n-sa[L]-he[L];
        return;
    }
    int ls=rt<<1,rs=ls|1,mid=(L+R)>>1;
    build(lson);
    build(rson);
    num[rt]=num[ls]+num[rs];
}
void getsa(char *st)
{
    int i,k,p,*x=T1,*y=T2;
    for(i=0; i<m; i++) ct[i]=0;
    for(i=0; i<n; i++) ct[x[i]=st[i]]++;
    for(i=1; i<m; i++) ct[i]+=ct[i-1];
    for(i=n-1; i>=0; i--)
        sa[--ct[x[i]]]=i;
    for(k=1,p=1; p<n; k<<=1,m=p)
    {
        for(p=0,i=n-k; i<n; i++) y[p++]=i;
        for(i=0; i<n; i++) if(sa[i]>=k) y[p++]=sa[i]-k;
        for(i=0; i<m; i++) ct[i]=0;
        for(i=0; i<n; i++) ct[x[y[i]]]++;
        for(i=1; i<m; i++) ct[i]+=ct[i-1];
        for(i=n-1; i>=0; i--) sa[--ct[x[y[i]]]]=y[i];
        for(swap(x,y),p=1,x[sa[0]]=0,i=1; i<n; i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
    }
}
void gethe(char *st)
{
    int i,j,k=0;
    for(i=0;i<n;i++) rk[sa[i]]=i;
    for(i=0;i<n-1;i++)
    {
        if(k) k--;
        j=sa[rk[i]-1];
        while(st[i+k]==st[j+k]) k++;
        he[rk[i]]=k;
    }
}
void rmq_init()
{
    int i,j;
    for(i=0;i<n;i++)
    {
        rmq[0][i]=he[i];
        id[0][i]=sa[i];
    }
    for(i=1;i<=lg[n];i++)
        for(j=0;j+(1<<i)-1<n;j++)
        {
            rmq[i][j]=min(rmq[i-1][j],rmq[i-1][j+(1<<(i-1))]);
            id[i][j]=min(id[i-1][j],id[i-1][j+(1<<(i-1))]);
        }
}
int rmq_min(int l,int r)
{
    if(l>r)
        return 0;
    int tmp=lg[r-l+1];
    return min(rmq[tmp][l],rmq[tmp][r-(1<<tmp)+1]);
}
int rmq_id(int l,int r)
{
    int tmp=lg[r-l+1];
    return min(id[tmp][l],id[tmp][r-(1<<tmp)+1]);
}
void prermq()
{
    int  i;
    lg[0]=-1;
    for(i=1;i<maxn;i++)
        lg[i]=lg[i>>1]+1;
}
void qu(int L,int R,int rt,ll k)
{
    if(k>num[rt])
    {
        pos=-1;
        le=ri=0;
        return;
    }
    if(L==R)
    {
        pos=L;
        len=he[L]+k;
        return;
    }
    int ls=rt<<1,rs=ls|1,mid=(L+R)>>1;
    if(num[ls]>=k)
        qu(lson,k);
    else
        qu(rson,k-num[ls]);
}
int binl(int x)
{
    int low=1,hi=x-1,mid,ans=x;

    while(low<=hi)
    {
        mid=(low+hi)>>1;
        if(rmq_min(mid+1,x)>=len)
            ans=mid,hi=mid-1;
        else
            low=mid+1;
    }
    return ans;
}
int binr(int x)
{
    int low=x+1,hi=n,mid,ans=x;

    while(low<=hi)
    {
        mid=(low+hi)>>1;
        if(rmq_min(x+1,mid)>=len)
            ans=mid,low=mid+1;
        else
            hi=mid-1;
    }
    return ans;
}
inline ll ReadInt()
{
    char ch = getchar();
    if (ch==EOF) return -1;
    ll data = 0;
    while (ch < '0' || ch > '9')
    {
        ch = getchar();
        if (ch==EOF) return -1;
    }
    do
    {
        data = data*10 + ch-'0';
        ch = getchar();
    } while (ch >= '0' && ch <= '9');
    return data;
}

inline void putit(int x)
{
    if (x/10>0) putit(x/10);
    putchar(x%10+'0');
}
int main()
{
    int q,lll,rrr;
    ll kth;

    prermq();
    while(~scanf("%s",txt))
    {
        m=150,n=strlen(txt);
        n++;
        getsa(txt);
        gethe(txt);
        rmq_init();
        n--;
        build(1,n,1);
        scanf("%d",&q);
        le=ri=0;
        while(q--)
        {
            kth=ReadInt();
            kth=(le^ri^kth)+1;
            qu(1,n,1,kth);
            if(pos==-1)
                putit(le),putchar(' '),putit(ri),putchar('\n');
            else
            {
                lll=binl(pos);
                rrr=binr(pos);
                le=rmq_id(lll,rrr)+1;
                ri=le+len-1;
                putit(le),putchar(' '),putit(ri),putchar('\n');
            }
        }
    }
    return 0;
}

hdu 5008(2014 ACM/ICPC Asia Regional Xi'an Online ) Boring String Problem(后缀数组&二分)

时间: 2024-08-01 22:48:09

hdu 5008(2014 ACM/ICPC Asia Regional Xi'an Online ) Boring String Problem(后缀数组&二分)的相关文章

HDU 5014 Number Sequence(2014 ACM/ICPC Asia Regional Xi&#39;an Online) 题解

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5014 Number Sequence Problem Description There is a special number sequence which has n+1 integers. For each number in sequence, we have two rules: ● ai ∈ [0,n] ● ai ≠ aj( i ≠ j ) For sequence a and sequ

2014 ACM/ICPC Asia Regional Xi&#39;an Online(HDU 5007 ~ HDU 5017)

题目链接 A题:(字符串查找,水题) 题意 :输入字符串,如果字符串中包含“ Apple”, “iPhone”, “iPod”, “iPad” 就输出 “MAI MAI MAI!”,如果出现 “Sony” 就输出“SONY DAFA IS GOOD!” ,大小写敏感. 思路 : 字符串查找,水题. 1 #include <string.h> 2 #include <stdio.h> 3 #include <iostream> 4 5 using namespace st

HDU 5014 Number Sequence 贪心 2014 ACM/ICPC Asia Regional Xi&#39;an Online

尽可能凑2^x-1 #include <cstdio> #include <cstring> const int N = 100005; int a[N], p[N]; int init(int x) { int cnt = 0; while(x > 1) { x /= 2; cnt ++; } return cnt + 1; } int main() { int n; while(~scanf("%d", &n)){ for(int i = 0;

HDU 5010 Get the Nut(2014 ACM/ICPC Asia Regional Xi&#39;an Online)

思路:广搜, 因为空格加上动物最多只有32个那么对这32个进行编号,就能可以用一个数字来表示状态了,因为只有 ‘P’   'S' 'M' '.' 那么就可以用4进制刚好可以用64位表示. 接下去每次就是模拟了. 注意:  ‘S’ 不是只有一个. 一个东西如果不是'P'在动的话要先判断周围有没有‘P’,有的话要先吃掉      'P'在动的时候如果一个位置周围有多个东西,都要吃掉. #include<iostream> #include<cstdio> #include<alg

hdu 5016 点分治(2014 ACM/ICPC Asia Regional Xi&#39;an Online)

Mart Master II Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 675    Accepted Submission(s): 237 Problem Description Trader Dogy lives in city S, which consists of n districts. There are n - 1

2014 ACM/ICPC Asia Regional Xi&#39;an Online 233 Matrix,hdu 5015

比赛的时候若是这题过了就进前50 刚开始的时候大家的思路都以为是找规律的题目,于是再推公式,此外还发现类似于杨辉三角.于是又去套杨辉三角的通项去求. 于是TLE了无数次.(每次取范围的最大值也要3s多). 对于明显的矩阵样子,其实可以转化为矩阵的运算,每一行的转移.就是对一个转移矩阵的幂运算.然后再用快速矩阵幂即可. A: 10 0 0 1 10 1 0 1 10 1 1 1 0  0  0 1 B: 23 0 0 3 C=A^M  *B,ans=C[N] 教训:对于时间限制,即便是最大数据也要

2014 ACM/ICPC Asia Regional Xi&#39;an Online

03 hdu5009 状态转移方程很好想,dp[i] = min(dp[j]+o[j~i]^2,dp[i]) ,o[j~i]表示从j到i颜色的种数. 普通的O(n*n)是会超时的,可以想到o[]最大为sqrt(n),问题是怎么快速找到从i开始往前2种颜色.三种.四种...o[]种的位置. 离散化之后,可以边走边记录某个数最后一个出现的位置,初始为-1,而所要求的位置就等于 if(last[a[i]]==-1) 该数没有出现过,num[i][1] = i,num[i][j+1] = num[i-1

HDU - 5008 Boring String Problem (后缀数组+二分+RMQ)

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 stri

HDU 5000 2014 ACM/ICPC Asia Regional Anshan Online DP

Clone Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/65536K (Java/Other) Total Submission(s) : 8   Accepted Submission(s) : 5 Font: Times New Roman | Verdana | Georgia Font Size: ← → Problem Description After eating food from Chernobyl,