• hdu 5008 Boring String Problem(后缀数组+rmq)


    题目链接:hdu 5008 Boring String Problem

    题意:

    给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那个。

    题解:

    后缀数组求完height后,求一下字典序第i的后缀有多少个不同的子串,然后求一下前缀和。

    然后就可以每对于一个k,可以二分求到排序后第一个字典序为k的后缀,然后用rmq求一下最小就行了。

     1 #include<bits/stdc++.h>
     2 #define mst(a,b) memset(a,b,sizeof(a))
     3 #define F(i,a,b) for(int i=(a);i<=(b);++i)
     4 #define ___ freopen("c:\code\in.txt","r",stdin);
     5 inline int RT(int l,int r){return l+r|l!=r;}
     6 using namespace std;
     7 typedef long long ll;
     8 typedef pair<int,int>P;
     9 
    10 namespace suffixarray{    
    11     #define FN(n) for(int i=0;i<n;i++)
    12     const int N =1E5+7;
    13     int rnk[N],sa[N],height[N],c[N];char s[N];
    14     void getsa(int n,int m,int *x=rnk,int *y=height){
    15         FN(m)c[i]=0;FN(n)c[x[i]=s[i]]++;FN(m)c[i+1]+=c[i];
    16         for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    17         for(int k=1,p;p=0,k<=n;k=p>=n?N:k<<1,m=p){
    18             for(int i=n-k;i<n;i++)y[p++]=i;
    19             FN(n)if(sa[i]>=k)y[p++]=sa[i]-k;
    20             FN(m)c[i]=0;FN(n)c[x[y[i]]]++;FN(m)c[i+1]+=c[i];
    21             for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
    22             swap(x,y),p=1,x[sa[0]]=0;
    23             for(int i=1;i<n;i++)
    24             x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
    25         }
    26         FN(n)rnk[sa[i]]=i;
    27         for(int i=0,j,k=0;i<n-1;height[rnk[i++]]=k)
    28         for(k=k?k-1:k,j=sa[rnk[i]-1];s[i+k]==s[j+k];k++);
    29     }
    30 }
    31 using namespace suffixarray;
    32 
    33 int n,q;
    34 ll k,sum[N],L,R;
    35 
    36 int a[N][18],b[N][18];
    37 void rmq(int *a,int f[][18])
    38 {
    39     for(int i=1;i<=n;i++)f[i][0]=a[i];
    40     for(int j=1;1<<j<n;j++)for(int i=1;i<=n;i++)
    41     if(i+(1<<j)-1<= n)f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
    42     else break;
    43 }
    44 inline int find(int l,int r,int f[][18])
    45 {
    46     int k=31-__builtin_clz(r-l+1);
    47     return min(f[l][k],f[r-(1<<k)+1][k]);
    48 }
    49 
    50 void getkth(ll k)
    51 {
    52     if(k>sum[n]){L=R=0;return;}
    53     int l=0,r=n,ans,mid;
    54     while(l<=r)
    55     {
    56         mid=l+r>>1;
    57         if(sum[mid]>=k)ans=mid,r=mid-1;
    58         else l=mid+1;
    59     }
    60     k=k-sum[ans-1]+height[ans];
    61     int pos=ans;
    62     l=2,r=n-pos+1,ans=1;
    63     while(l<=r)
    64     {
    65         mid=l+r>>1;
    66         if(find(pos+1,pos+mid-1,a)>=k)l=mid+1,ans=mid;
    67         else r=mid-1;
    68     }
    69     L=find(pos,pos+ans-1,b)+1,R=L+k-1;
    70 }
    71 
    72 int main(){
    73     while(~scanf("%s",s))
    74     {
    75         L=R=0,getsa((n=strlen(s))+1,150);
    76         F(i,1,n)sum[i]=n-sa[i]-height[i]+sum[i-1];
    77         rmq(height,a),rmq(sa,b);
    78         scanf("%d",&q);
    79         while(q--)
    80         {
    81             scanf("%lld",&k);
    82             k=(k^L^R)+1,getkth(k);
    83             printf("%lld %lld
    ",L,R);
    84         }
    85     }
    86     return 0;
    87 }
    View Code
  • 相关阅读:
    2018第一发:记一次【Advanced Installer】打包之旅
    Nginx 实现端口转发
    php支付宝手机网页支付类实例
    磁盘阵列操作实战
    错误修改/etc/fstab,导致系统无法开机
    linux 查看机器的cpu,操作系统等命令
    shell实现https登录
    linux tomcat配置https
    ArrayList和Vector以及synchronizedList
    java synchronized修饰普通方法,修饰静态方法,修饰代码块,修饰线程run方法 比较
  • 原文地址:https://www.cnblogs.com/bin-gege/p/7510693.html
Copyright © 2020-2023  润新知