zoukankan      html  css  js  c++  java
  • 【转】HDU 6194 string string string (2017沈阳网赛-后缀数组)

    转自:http://blog.csdn.net/aozil_yang/article/details/77929216


    题意:

    告诉你一个字符串和k , 求这个字符串中有多少不同的子串恰好出现了k 次。

    思路:

    后缀数组。

    我们先考虑至少出现k 次的子串, 所以我们枚举排好序的后缀i (sa[i]) 。

    k段k 段的枚举。

    假设当前枚举的是 sa[i]~sa[i + k -1]

    那么假设这一段的最长公共前缀  是L 的话。

    那么就有L 个不同的子串至少出现了k次。

    我们要减去至少出现k + 1次的 , 但还要和这个k 段的lcp 有关系, 因此肯定就是 这一段 向上找一个后缀 或者向下找一个后缀。

    即  sa[i-1] ~ sa[i + k - 1]  和 sa[i] ~ sa[i + k] 求两次lcp 减去即可。

    但是会减多了。

    减多的显然是sa[i-1] ~ sa[i + k] 的lcp。 加上即可。

    注意 k =1的情况在求lcp 会有 问题, 即求一个串的最长公共前缀会有问题, 特判一下即可。

    一定要注意边界问题 边界问题 边界问题!!!


      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 using namespace std;
      5 
      6 const int maxn = 100000 + 10;
      7 
      8 int t1[maxn], t2[maxn], c[maxn];
      9 
     10 bool cmp(int* r, int a,int b,int l){
     11     return r[a] == r[b] && r[a+l] == r[b+l];
     12 }
     13 
     14 void da(int str[], int sa[], int Rank[], int lcp[], int n, int m){
     15     ++n;
     16     int i, j, p, *x = t1, *y = t2;
     17     for (i = 0; i < m; ++i) c[i] = 0;
     18 //        puts("hha");
     19     for (i = 0; i < n; ++i) c[x[i] = str[i] ]++;
     20     for (i = 1; i < m; ++i) c[i] += c[i-1];
     21     for (i = n-1; i >= 0; --i) sa[--c[x[i] ] ] = i;
     22     for (j = 1; j <= n; j <<= 1){
     23         p = 0;
     24         for (i = n-j; i < n; ++i) y[p++] = i;
     25         for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j;
     26         for (i = 0; i < m; ++i) c[i] = 0;
     27         for (i = 0; i < n; ++i) c[x[y[i] ] ]++;
     28 
     29         for (i = 1; i < m; ++i) c[i] += c[i-1];
     30         for (i = n-1; i >= 0; --i) sa[--c[x[y[i] ] ] ] = y[i];
     31 
     32         swap(x,y);
     33         p = 1; x[sa[0] ] = 0;
     34         for (i = 1; i < n; ++i){
     35             x[sa[i] ] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++;
     36 
     37 
     38         }
     39 
     40         if (p >= n)break;
     41         m= p;
     42 
     43 
     44     }
     45 
     46     int k = 0;
     47     n--;
     48     for (i = 0; i <= n; ++i) Rank[sa[i] ] = i;
     49     for (i = 0; i < n; ++i){
     50         if (k)--k;
     51         j = sa[Rank[i]-1 ];
     52         while(str[i+k] == str[j+k])++k;
     53         lcp[Rank[i] ] = k;
     54     }
     55 }
     56 
     57 int lcp[maxn], a[maxn], sa[maxn], Rank[maxn];
     58 
     59 char s[maxn];
     60 
     61 int d[maxn][40];
     62 int len;
     63 
     64 void rmq_init(int* A, int n){
     65     for (int i = 0; i < n; ++i) d[i][0] = A[i];
     66     for (int j = 1; (1<<j) <= n; ++j)
     67         for (int i = 0; i + (1<<j) - 1 < n ; ++i)
     68             d[i][j] = min(d[i][j-1], d[i + (1<< (j-1))][j-1]);
     69 }
     70 
     71 int ASK(int l,int r){
     72     int k = 0;
     73     while((1<<(k+1)) <= r-l + 1)++k;
     74     return min(d[l][k], d[r-(1<<k) + 1][k]);
     75 }
     76 
     77 int ask(int l,int r){
     78     if (l == r) return len - sa[r]; /// l == r的话 是一个串, 返回本身的长度即可。
     79     return ASK(l + 1, r); ///否则在rmq查询。
     80 }
     81 
     82 //
     83 int main(){
     84     int T;
     85     scanf("%d", &T);
     86 
     87     while(T--){
     88         int k;
     89         scanf("%d", &k);
     90         scanf("%s", s);
     91         len = strlen(s);
     92         for (int i = 0; i < len; ++i){
     93             a[i] = s[i] - 'a' + 1;
     94         }
     95         a[len] = 0;
     96         da(a, sa, Rank, lcp, len, 30);
     97         rmq_init(lcp, len + 1);
     98         long long ans = 0;
     99         for (int i = 1; i + k - 1 <= len; ++i){
    100             ans += ask(i, i + k - 1);
    101             if (i - 1 > 0)ans -= ask(i - 1, i + k - 1); ///注意边界问题。
    102             if (i + k <= len)ans -= ask(i, i + k);
    103             if (i - 1 > 0 && i + k <= len)ans += ask(i - 1 , i + k);
    104         }
    105         printf("%I64d
    ", ans);
    106 
    107 
    108     }
    109     return 0;
    110 }
    111 
  • 相关阅读:
    浏览器内核
    为什么一般请求可以下载文件,Ajax 请求就不能下载
    转 深入理解javascript原型和闭包(10)——this
    node读取文本文件时,去掉BOM
    AMD & CMD
    gulp requirejs Error: ENOENT: no such file or directory, open '/js/require_config.js', 一直报找不到require_config.js,坑死了
    [BZOJ3224]普通平衡树
    [NOIP2014D2]
    [NOIP2014D1]
    [NOIP2013D2]
  • 原文地址:https://www.cnblogs.com/liuzhanshan/p/7507267.html
Copyright © 2011-2022 走看看