• HDU 5558 后缀数组+二分


    题意有一些绕,但其实就是对于不断变化的i,求以j(0=j<i)使得suffix[j]与suffix[i]的最长公共前缀最长,如果有多个j,则取最小的j。

    可以在rank数组中二分,在1-rank[i-1]中二分最接近i的j使得sa[j]小于i,通俗地说就是rank比的rank[i]小,并且位于i之前的后缀。因为这个是左边最接近rank[i]的,所以与suffix[i]的最长公共前缀一定是满足最大的。接下来再根据得到的LCP值,二分一个最小的j。同理,再从rank[i+1]到rank[n]中作类似二分。两者结合得到当前的K和T。

    其实这道题中间过程也可以不用二分,直接向左右暴力扫。速度会快很多。

      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=1e5+10;
     18 
     19 
     20 int MIN(int a,int b) {
     21     return a<b?a:b;
     22 }
     23 int MAX(int a,int b) {
     24     return a>b?a:b;
     25 }
     26 
     27 int val[N];
     28 struct RMQ {
     29     int dp[N][22];
     30     int (*cmp) (int,int);
     31     void setMin() {
     32         cmp=MIN;
     33     }
     34     void setMax() {
     35         cmp=MAX;
     36     }
     37     void init(int n,int *val) {
     38         for (int i=0; i<=n; i++)
     39             dp[i][0]=val[i];
     40         for (int j=1; (1<<j)<=n; j++) {
     41             int k=1<<(j-1);
     42             for (int i=0; i+k<=n; i++)
     43                 dp[i][j]=cmp(dp[i][j-1],dp[i+k][j-1]);
     44         }
     45     }
     46     int query(int a,int b) {
     47         if (a>b) swap(a,b);
     48         int dis=b-a+1;
     49         int k=log((double)dis)/log(2.0);
     50         return cmp(dp[a][k],dp[b-(1<<k)+1][k]);
     51     }
     52 } rmq;
     53 
     54 char s[N];
     55 struct SuffixArray {
     56     int wa[N], wb[N], cnt[N], wv[N];
     57     int rk[N], height[N];
     58     int sa[N];
     59     bool cmp(int r[], int a, int b, int l) {
     60         return r[a] == r[b] && r[a+l] == r[b+l];
     61     }
     62     void calcSA(char r[], int n, int m) {
     63         int i, j, p, *x = wa, *y = wb;
     64         for (i = 0; i < m; ++i) cnt[i] = 0;
     65         for (i = 0; i < n; ++i) cnt[x[i]=r[i]]++;
     66         for (i = 1; i < m; ++i) cnt[i] += cnt[i-1];
     67         for (i = n-1; i >= 0; --i) sa[--cnt[x[i]]] = i;
     68         for (j = 1, p = 1; p < n; j *= 2, m = p) {
     69             for (p = 0, i = n - j; i < n; ++i) y[p++] = i;
     70             for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
     71             for (i = 0; i < n; ++i) wv[i] = x[y[i]];
     72             for (i = 0; i < m; ++i) cnt[i] = 0;
     73             for (i = 0; i < n; ++i) cnt[wv[i]]++;
     74             for (i = 1; i < m; ++i) cnt[i] += cnt[i-1];
     75             for (i = n-1; i >= 0; --i) sa[--cnt[wv[i]]] = y[i];
     76             for (swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i)
     77                 x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
     78         }
     79     }
     80     void calcHeight(char r[], int n) {
     81         int i, j, k = 0;
     82         for (i = 1; i <= n; ++i) rk[sa[i]] = i;
     83         for (i = 0; i < n; height[rk[i++]] = k)
     84             for (k?k--:0, j = sa[rk[i]-1]; r[i+k] == r[j+k]; k++);
     85     }
     86     int lcp(int a,int b,int len) {
     87         if (a==b) return len-a;
     88         int ra=rk[a],rb=rk[b];
     89         if (ra>rb) swap(ra,rb);
     90         return queryST(ra+1,rb);
     91     }
     92     int st[N][22];
     93     int preLog2[N];
     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         preLog2[1]=0;
    103         for(int i=2;i<=n;i++){
    104             preLog2[i]=preLog2[i-1]+((i&(i-1))==0);
    105         }
    106     }
    107     int queryST(int a,int b) {
    108         if (a>b) swap(a,b);
    109         int dis=b-a+1;
    110         int k=preLog2[dis];
    111         return min(st[a][k],st[b-(1<<k)+1][k]);
    112     }
    113     void solve(int n) {
    114         calcSA(s,n+1,128);
    115         calcHeight(s,n);
    116         initST(n);
    117         rmq.setMin();
    118         rmq.init(n,sa);
    119         printf("-1 %d
    ",s[0]);
    120         int i=1;
    121         while (i<n) {
    122             int l=1,r=rk[i]-1;
    123             int k=-1,t=s[i];
    124             int minIndex=-1;
    125             while (l<=r) {
    126                 int mid=(l+r)>>1;
    127                 int minSA=rmq.query(mid,rk[i]-1);
    128                 if (minSA<i)
    129                     l=mid+1,minIndex=minSA;
    130                 else
    131                     r=mid-1;
    132             }
    133             if (minIndex!=-1) {
    134                 int u=lcp(minIndex,i,n);
    135                 if (u) {
    136                     k=u;
    137                     int l=1,r=rk[i]-1,ret=-1;
    138                     while (l<=r) {
    139                         int mid=(l+r)>>1;
    140                         int curLCP=lcp(sa[mid],i,n);
    141                         if (curLCP>=u)
    142                             r=mid-1,ret=mid;
    143                         else l=mid+1;
    144                     }
    145                     t=rmq.query(ret,rk[i]-1);
    146                 }
    147             }
    148             l=rk[i]+1;
    149             r=n;
    150             minIndex=-1;
    151             while (l<=r) {
    152                 int mid=(l+r)>>1;
    153                 int minSA=rmq.query(rk[i]+1,mid);
    154                 if (minSA<i)
    155                     r=mid-1,minIndex=minSA;
    156                 else
    157                     l=mid+1;
    158             }
    159             if (minIndex!=-1) {
    160                 int u=lcp(minIndex,i,n);
    161                 if (u&&u>=k) {
    162                     if (u==k)
    163                         t=min(t,minIndex);
    164                     else
    165                         t=minIndex;
    166                     k=u;
    167                     int l=rk[i]+1,r=n,ret=-1;
    168                     while (l<=r) {
    169                         int mid=(l+r)>>1;
    170                         int curLCP=lcp(sa[mid],i,n);
    171                         if (curLCP>=u)
    172                             l=mid+1,ret=mid;
    173                         else r=mid-1;
    174                     }
    175                     t=min(t,rmq.query(rk[i]+1,ret));
    176                 }
    177             }
    178             if (k==-1) {
    179                 printf("-1 %d
    ",s[i]);
    180                 i++;
    181             } else {
    182                 printf("%d %d
    ",k,t);
    183                 i+=k;
    184             }
    185         }
    186     }
    187 } suf;
    188 
    189 int main () {
    190     int T;
    191     scanf("%d",&T);
    192     while (T--) {
    193         scanf("%s",s);
    194         int n=strlen(s);
    195         static int cas=1;
    196         printf("Case #%d:
    ",cas++);
    197         suf.solve(n);
    198     }
    199     return 0;
    200 }
  • 相关阅读:
    C++中使用多线程
    hdu 4223 dp 求连续子序列的和的绝对值最小值
    hdu 1372 bfs 计算起点到终点的距离
    hdu 4217 线段树 依次取第几个最小值,求其sum
    心得
    hdu 1175 bfs 按要求进行搜索,是否能到达,抵消两个(相同)棋子
    hdu 4221 greed 注意范围 工作延期,使整个工作时间罚时最少的单个罚时最长的值
    hdu 2844 多重背包 多种硬币,每一种硬币有一点数量,看他能组成多少种钱
    uva LCDDisplay
    hdu 4218 模拟 根据一个圆点和半径画一个圆 注意半径要求
  • 原文地址:https://www.cnblogs.com/micrari/p/4993279.html
Copyright © 2020-2023  润新知