hdu 5853 Jong Hyok and String (二分+后缀数组+RMQ)

来源:互联网 发布:风险矩阵分析法 编辑:程序博客网 时间:2024/04/27 17:51

Jong Hyok and String

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 301    Accepted Submission(s): 66


Problem Description
Jong Hyok loves strings. One day he gives a problem to his friend you. He writes down n strings Pi in front of you, and asks m questions. For i-th question, there is a string Qi. We called strange set(s) = {(i, j) | s occurs in Pi and j is the position of its last character in the current occurence}. And for ith question, you must answer the number of different strings t which satisfies strange set(Qi) = strange set(t) and t is a substring of at least one of the given n strings.
 

Input
First line contains T, a number of test cases.

For each test cases, there two numbers n, m and then there are n strings Pi and m strings Qj.(i = 1…n, j = 1…m)


1 <= T <= 10
1 <= n <= 100000
1 <= m<= 500000
1 <=|Pi|<=100000
1 <=|Qi|<=100000

ni=1|Pi|100000
File size is less than 3.5 megabytes.

 

Output
For each test case, first line contains a line “Case #x:”, x is the number of the case.

For each question, you should print one integer in one line.

 

Sample Input
12 2abaabaab
 

Sample Output
Case #1:12
Hint
strange set(“a”) ={(1, 1), (1, 3), (2, 1)}.strange set(“ab”) ={(1, 2), (2, 2)}.strange set(“b”) ={(1, 2), (2, 2)}.
分析:考虑到P串长度总和为10w,我们把每个P串倒着连成一串,中间用特殊符隔开,由于特殊符号需要10w个,所以我们要把字符换成int,然后跑后缀数组,就可以得到每个后缀的排名,查询时也把Q串倒序,并换成int,然后去每个后缀里面找哪些可以和这个倒序的Q串匹配,由于每个后缀已经排好序,所以我们用二分查找得到下界lower和上界upper,如果找不到,那么答案就是0。先定义一个maxlen,如果lower==upper,那么maxlen为排名为lower的这个后缀的不包含特殊符的最大前缀,如果lower<upper,那么maxlen=min(height[lower+1]...height[upper]),这里取最小值可以用RMQ处理height值得到,然后最后的答案ans=maxlen-max(height[lower],height[upper+1])
#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<vector>#include<algorithm>using namespace std;const int N=200010;const int maxn=100010;int cmp(int *r,int a,int b,int l){    return (r[a]==r[b])&&(r[a+l]==r[b+l]);}int wa[N],wb[N],ws[N],wv[N];int Rank[N],height[N];void DA(int *r,int *sa,int n,int m){    int i,j,p,*x=wa,*y=wb,*t;    for(i=0;i<m;i++) ws[i]=0;    for(i=0;i<n;i++) ws[x[i]=r[i]]++;    for(i=1;i<m;i++) ws[i]+=ws[i-1];    for(i=n-1;i>=0;i--) sa[--ws[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++) ws[i]=0;        for(i=0;i<n;i++) ws[wv[i]]++;        for(i=1;i<m;i++) ws[i]+=ws[i-1];        for(i=n-1;i>=0;i--) sa[--ws[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++;    }    int k=0;    for(i=1;i<n;i++) Rank[sa[i]]=i;    for(i=0;i<n-1; height[Rank[i++]] = k )    for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++);}char s[maxn];int a[maxn];int r[N],sa[N],C[N][20];int pos[N];void rmq(int nn){    for(int i=1;i<nn;i++) C[i][0]=height[i];    for(int j=1;(1<<j)<nn;j++)        for(int i=1;i+(1<<j)-1<nn;i++)        C[i][j]=min(C[i][j-1],C[i+(1<<(j-1))][j-1]);}int getmin(int l,int r){    int k=0;    while((1<<(k+1))<=r-l+1) k++;    return min(C[l][k],C[r-(1<<k)+1][k]);}int cmp(int pos,int len,int num){    for(int i=0;i<len;i++)    {        if(r[i+pos]>a[i]) return 1;        else if(r[i+pos]<a[i]) return -1;    }    return 0;}int main(){    int T;    scanf("%d",&T);    for(int ca=1;ca<=T;ca++)    {        int n,m;        scanf("%d%d",&n,&m);        int num=0;        for(int i=1;i<=n;i++)        {            scanf("%s",s);            int len=strlen(s);            reverse(s,s+len);            int mm=num+len-1;            for(int j=0;j<len;j++)            {                pos[num]=mm;                r[num++]=s[j]-'a'+1;            }            r[num++]=26+i;        }        r[num++]=0;        DA(r,sa,num,n+27);        height[num]=0;        rmq(num);        printf("Case #%d:\n",ca);        while(m--)        {            scanf("%s",s);            int len=strlen(s);            reverse(s,s+len);            for(int i=0;i<len;i++)                a[i]=s[i]-'a'+1;            int lower=-1,upper=-1;            int L,R;            L=1,R=num-1;            while(L<=R)            {                int mid=(L+R)>>1;                int k=cmp(sa[mid],len,num);                if(k==0)                {                    lower=mid;                    R=mid-1;                }                else if(k==1) R=mid-1;                else L=mid+1;            }            L=1,R=num-1;            while(L<=R)            {                int mid=(L+R)>>1;                int k=cmp(sa[mid],len,num);                if(k==0)                {                    upper=mid;                    L=mid+1;                }                else if(k==1) R=mid-1;                else L=mid+1;            }            if(lower==-1)            {                puts("0");                continue;            }            if(lower==upper)            {                printf("%d\n",(pos[sa[lower]]-sa[lower]+1)-max(height[lower],height[lower+1]));                continue;            }            int ans=getmin(lower+1,upper)-max(height[lower],height[upper+1]);            printf("%d\n",ans);        }    }    return 0;}

 

0 0
原创粉丝点击