• 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
  • 相关阅读:
    POJ 2184 Cow Exhibition (01背包变形)(或者搜索)
    ACM-ICPC如何起步[转]
    查看centos中的用户和用户组和修改密码
    CentOS7安装并配置PostgreSQL
    在Win10下,python3和python2同时安装并解决pip共存问题
    Django-用户-组-权限
    linux系统磁盘满了,怎么解决?
    DRF (Django REST framework) 中的路由Routers
    DRF (Django REST framework) 中的视图扩展类
    DRF (Django REST framework) 中的视图类
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7464153.html
Copyright © 2020-2023  润新知