zoukankan      html  css  js  c++  java
  • hdu3518(后缀数组)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3518

    题意: 给出一个字符串, 问其中有多少字串出现了两次以上(计算次数时不能彼此覆盖, 如 "aaaa"  中 "aa" 出现了两次而非三次).

    思路: 后缀数组/字典树

    后缀数组解法, 题目所求即使用后缀中出现两次以上的前缀数目. 可以枚举前缀长度, 将满足条件的前缀累进答案中. 在 SA 数组中, 具有相同前缀的后缀肯定是在一个连续块中的. 可以用 height 数组的性质来区分当前长度有哪些前缀块. 注意满足条件的前缀块中至少存在两个彼此不覆盖的前缀.

    代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define rank Rank
     5 using namespace std;
     6 
     7 const int MAXN = 1e4 + 10;
     8 char str[MAXN];
     9 int SA[MAXN], rank[MAXN], height[MAXN], sum[MAXN], tp[MAXN], a[MAXN];
    10 
    11 bool cmp(int *f, int x, int y, int w){
    12     return f[x] == f[y] && f[x + w] == f[y + w];
    13 }
    14 
    15 void get_SA(int *s, int n, int m){
    16     for(int i = 0; i < m; i++) sum[i] = 0;
    17     for(int i = 0; i < n; i++) sum[rank[i] = s[i]]++;
    18     for(int i = 1; i < m; i++) sum[i] += sum[i - 1];
    19     for(int i = n - 1; i >= 0; i--) SA[--sum[rank[i]]] = i;
    20     for(int len = 1; len <= n; len <<= 1){
    21         int p = 0;
    22         for(int i = n - len; i < n; i++) tp[p++] = i;//后面i个数没有第二关键字,即第二关键字为空,所以最小
    23         for(int i = 0; i < n; i++){
    24             if(SA[i] >= len) tp[p++] = SA[i] - len;
    25         }
    26         //tp[i]存储按第二关键字排序第i的下标
    27         //对第二关键字排序的结果再按第一关键字排序,和长度为1的情况类似
    28         for(int i = 0; i < m; i++) sum[i] = 0;
    29         for(int i = 0; i < n; i++) sum[rank[tp[i]]]++;
    30         for(int i = 1; i < m; i++) sum[i] += sum[i - 1];
    31         for(int i = n - 1; i >= 0; i--) SA[--sum[rank[tp[i]]]] = tp[i];
    32         //根据SA和rank数组重新计算rank数组
    33         swap(rank, tp);//交换后tp指向旧的rank数组
    34         p = 1;
    35         rank[SA[0]] = 0;
    36         for(int i = 1; i < n; i++){
    37             rank[SA[i]] = cmp(tp, SA[i - 1], SA[i], len) ? p - 1 : p++;
    38         }
    39         if(p >= n) break;
    40         m = p;//下次基数排序的最大值
    41     }
    42     //求height
    43     int k = 0;
    44     n--;
    45     for(int i = 0; i <= n; i++) rank[SA[i]] = i;
    46     for(int i = 0; i < n; i++){
    47         if(k) k--;
    48         int j = SA[rank[i] - 1];
    49         while(s[i + k] == s[j + k]) k++;
    50         height[rank[i]] = k;
    51     }
    52 }
    53 
    54 int main(void){
    55     while(~scanf("%s", str)){
    56         if(str[0] == '#') break;
    57         int len = strlen(str), sol = 0;
    58         for(int i = 0; i < len; i++) a[i] = str[i];
    59         a[len] = 0;
    60         get_SA(a, len + 1, 128);
    61         for(int i = 1; i <= len / 2; i++){
    62             int l = MAXN, r = 0;
    63             for(int j = 2; j <= len; j++){
    64                 if(height[j] >= i){
    65                     l = min(l, min(SA[j], SA[j - 1]));
    66                     r = max(r, max(SA[j], SA[j - 1]));
    67                 }else{
    68                     if(r - l >= i) sol++;
    69                     l = MAXN;
    70                     r = 0;
    71                 }
    72             }
    73             if(r - l >= i) sol++;
    74         }
    75         printf("%d
    ", sol);
    76     }
    77     return 0;
    78 }
    View Code
  • 相关阅读:
    关于lucene断点续索引和增量索引的问题
    发布一个关于统计时间段的MDX语句
    【蛙蛙推荐】想设计一个关于软件开发的元搜索引擎,希望大家支持
    python中and和or的用法
    Hadoop实战中高级部分 之 Hadoop MapReduce高级编程
    (转)对实时分析与离线分析的思考(二)
    数据分析站点导航
    MapReduce:详解Shuffle过程
    分析能力的8个等级(My Level)
    (转)Tire Tree
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7464153.html
Copyright © 2011-2022 走看看