zoukankan      html  css  js  c++  java
  • HDU 5008 求第k小子串

    本题要求第k小的distinct子串,可以根据height数组,二分出这个第k小子串所在后缀的位置信息。由于题目要求子串起始下标尽可能小。所以再在rank数组中,二分出与当前后缀LCP大于等于所求子串长度的范围。通过RMQ求出这个范围中最小的sa。

      1 #include <iostream>
      2 #include <vector>
      3 #include <algorithm>
      4 #include <string>
      5 #include <string.h>
      6 #include <stdio.h>
      7 #include <queue>
      8 #include <stack>
      9 #include <map>
     10 #include <set>
     11 #include <cmath>
     12 #include <ctime>
     13 #include <cassert>
     14 #include <sstream>
     15 using namespace std;
     16 
     17 const int N=123456;
     18 
     19 int MIN(int a,int b){return a<b?a:b;}
     20 int MAX(int a,int b){return a>b?a:b;}
     21 
     22 int val[N];
     23 struct RMQ {
     24     int dp[N][22];
     25     int (*cmp) (int,int);
     26     void setMin(){cmp=MIN;}
     27     void setMax(){cmp=MAX;}
     28     void init(int n,int *val) {
     29         for (int i=1; i<=n; i++)
     30             dp[i][0]=val[i];
     31         for (int j=1; (1<<j)<=n; j++) {
     32             int k=1<<(j-1);
     33             for (int i=1; i+k<=n; i++)
     34                 dp[i][j]=cmp(dp[i][j-1],dp[i+k][j-1]);
     35         }
     36     }
     37     int query(int a,int b) {
     38         if (a>b) swap(a,b);
     39         int dis=b-a+1;
     40         int k=log((double)dis)/log(2.0);
     41         return cmp(dp[a][k],dp[b-(1<<k)+1][k]);
     42     }
     43 }rmq;
     44 char s[N];
     45 struct SuffixArray {;
     46     int sa[N];
     47     int t1[N],t2[N],c[N];
     48     int rk[N],height[N];
     49     long long sum[N];
     50     inline int cmp(int *r,int a,int b,int l){
     51         return r[a]==r[b]&&r[a+l]==r[b+l];
     52     }
     53     void calcSA (char *s,int n,int m) {
     54         int i,j,p,*x=t1,*y=t2;
     55         for(i=0;i<m;i++)c[i]=0;
     56         for(i=0;i<n;i++)c[x[i]=s[i]]++;
     57         for(i=1;i<m;i++)c[i]+=c[i-1];
     58         for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
     59         for(j=1;j<=n;j<<=1){
     60             p=0;
     61             for(i=n-j;i<n;i++)y[p++]=i;
     62             for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p
     63             for(i=0;i<m;i++)c[i]=0;
     64             for(i=0;i<n;i++)c[x[y[i]]]++;
     65             for(i=1;i<m;i++)c[i]+=c[i-1];
     66             for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa
     67             swap(x,y);
     68             p=1;x[sa[0]]=0;
     69             for(i=1;i<n;i++)
     70                 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     71             if(p>=n)break;
     72             m=p;
     73         }
     74     }
     75     void calcHeight(char *s,int n) {
     76         int i,j,k=0;
     77         for(i=0;i<=n;i++)rk[sa[i]]=i;
     78         for(i=0;i<n;i++){
     79             if(k)k--; // h[i]>=h[i-1]-1
     80             j=sa[rk[i]-1]; // suffix(j)排名在suffix(i)前一位
     81             while(s[i+k]==s[j+k])k++; // 暴力计算lcp
     82             height[rk[i]]=k;
     83         }
     84         sum[0]=0;
     85         for (int i=1;i<=n;i++) sum[i]=sum[i-1]+n-sa[i]-height[i];
     86     }
     87     int lcp(int a,int b,int len) {
     88         if (a==b) return len-a;
     89         int ra=rk[a],rb=rk[b];
     90         if (ra>rb) swap(ra,rb);
     91         return queryST(ra+1,rb);
     92     }
     93     int st[N][25];
     94     void initST(int n) {
     95         for (int i=1;i<=n;i++)
     96             st[i][0]=height[i];
     97         for (int j=1;(1<<j)<=n;j++) {
     98             int k=1<<(j-1);
     99             for (int i=1; i+k<=n; i++)
    100                 st[i][j]=min(st[i][j-1],st[i+k][j-1]);
    101         }
    102     }
    103     int queryST(int a,int b) {
    104         if (a>b) swap(a,b);
    105         int dis=b-a+1;
    106         int k=log((double)dis)/log(2.0);
    107         return min(st[a][k],st[b-(1<<k)+1][k]);
    108     }
    109     void solve(int &l,int &r,long long k,int n) {
    110         if (k<1||k>sum[n]) {
    111             l=0;r=0;
    112             return;
    113         }
    114         int t=lower_bound(sum,sum+n+1,k)-sum;
    115         assert(t>=1&&t<=n);
    116         long long now=sum[t-1];
    117         int need=k-now;
    118         l=sa[t],r=sa[t]+height[t]+need-1;
    119         int len=r-l+1;
    120         int le=t,ri=n,ret=l;
    121         while (le<=ri) {
    122             int mid=(le+ri)/2;
    123             if (lcp(sa[mid],l,n)>=len) {
    124                 le=mid+1;
    125                 ret=mid;
    126             } else ri=mid-1;
    127         }
    128         l=rmq.query(t,ret);
    129         l++;
    130         r=l+len-1;
    131     }
    132 }suf;
    133 
    134 int main () {
    135     while (scanf("%s",s)!=EOF) {
    136         int n=strlen(s);
    137         suf.calcSA(s,n+1,128);
    138         suf.calcHeight(s,n);
    139         suf.initST(n);
    140         rmq.setMin();
    141         rmq.init(n,suf.sa);
    142         int Q;
    143         scanf("%d",&Q);
    144         int l=0,r=0; //int cnt=0;
    145         while (Q--) {
    146             long long k;
    147             scanf("%I64d",&k);
    148             k^=(l^r);
    149             k++;
    150             //k=++cnt;
    151             suf.solve(l,r,k,n);
    152             printf("%d %d
    ",l,r);
    153         }
    154     }
    155     return 0;
    156 }
    View Code
  • 相关阅读:
    Windows 系统里面的 hosts 文件
    JDK 安装目录中 native2ascii.exe 命令详解
    火狐浏览器安装 Modify Headers 插件
    java iterator
    HashSet HashTable HashMap的区别
    c# 序列化
    Oracle 同步
    QL Server 高可用性(一)AlwaysOn 技术
    sqlserver 日志传送
    oracle forall
  • 原文地址:https://www.cnblogs.com/micrari/p/4993382.html
Copyright © 2011-2022 走看看