zoukankan      html  css  js  c++  java
  • 【spoj705】 Distinct Substrings

    【题目描述】

    给定一个字符串,计算其不同的子串个数。

    【输入格式】

    一行一个仅包含大写字母的字符串,长度<=50000

    【输出格式】

    一行一个正整数,即不同的子串个数。

    【样例输入】

    ABABA

    【样例输出】

    9

    【思路】
      一看就知道是后缀数组题啦~但是我不会写QAQ。。只好现学现用啦~
      在字符串最后补上一个'$',不因为别的只因为它比‘A’还要小。。不然你补ascII码是0的也可以。。
      申请rank数组和sa数组,rank[i]=j代表后缀i排第j位,sa[i]=j代表排名第i的是后缀j。也就是说rank和sa是相反的运算。
      首先将sa数组按照单字母的顺序排个序,更新rank数组,不过记得字母相同的排名也要相同,也就是如果str[sa[i]]==str[sa[i-1]]的话rank[sa[i]]=rank[sa[i-1]];else rank[sa[i]]=rank[sa[i-1]]+1;
      
    然后将k从0开始枚举,每次继续对sa进行排序,但是是以rank[sa[i]]为第一关键字,rank[sa[i]+2k]为第二关键字排序。
      在Trank中(其实就是tmpRank)更新好新的rank值,一样记得如果rank[sa[i]]==rank[sa[i-1]]&&rank[sa[i]+2k]==rank[sa[i-1]+2k]的话排名不要上升。
      重复这一步,直到2k>=n或者所有后缀的排名都不同。
      然后正常情况下k增加logN次,每次如果用计数排序只要O(N),一共O(NlogN)。
      但是不会写计数排序啊QAQ。。所以用快排好了。。多加一个log,一般不会被卡的吧。。
      计算出来sa和rank之后还要计算height数组,height[i]代表sa[i]和sa[i-1]的最长公共前缀,如果按照1——n的顺序计算的话是O(N2)的,显然不够优秀,于是我们按照一种奇怪的顺序计算。
      先算height[rank[1]],然后是height[rank[2]]……
      这样的话就会有一个性质:height[rank[i]]>=height[rank[i-1]]-1
      我也不知道为什么但是就是这样的。。
      然后就没有然后了。。
      我们知道任何一个子串都是某一个后缀的一个前缀
      对于后缀i来说,有length-i个前缀,其中有height[i]个和前一个后缀相同
      所以答案就是Σlength-i-height[i]

     1 #include <iostream>
     2 #include <cstring>
     3 #include <string>
     4 #include <cstdio>
     5 #include <cstdlib>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <queue>
     9 #include <stack>
    10 #include <map>
    11 #include <set>
    12 #include <list>
    13 #include <vector>
    14 #include <ctime>
    15 #include <functional>
    16 #define pritnf printf
    17 #define scafn scanf
    18 #define sacnf scanf
    19 #define For(i,j,k) for(int i=(j);i<=(k);(i)++)
    20 #define Clear(a) memset(a,0,sizeof(a))
    21 using namespace std;
    22 typedef unsigned int Uint;
    23 const int INF=0x3fffffff;
    24 const double eps=1e-10;
    25 ///==============struct declaration==============
    26 
    27 ///==============var declaration=================
    28 const int MAXN=50010;
    29 int n,k;
    30 int sa[MAXN],rank[MAXN],h[MAXN],trank[MAXN],height[MAXN];
    31 char str[MAXN];
    32 ///==============function declaration============
    33 bool cmp(int a,int b){return rank[a]==rank[b]?rank[a+(1<<k)]<rank[b+(1<<k)]:rank[a]<rank[b];}
    34 bool cmp1(int a,int b){return str[a]<str[b];}
    35 ///==============main code=======================
    36 int main()
    37 {
    38     scanf("%s",str+1);
    39     n=strlen(str+1);str[n+1]='$';n++;
    40     for(int i=0;i<=n;i++)
    41         sa[i]=i;
    42     sort(sa+1,sa+1+n,cmp1);
    43     rank[sa[1]]=1;
    44     for(int i=2;i<=n;i++)
    45         if (str[sa[i]]!=str[sa[i-1]])
    46             rank[sa[i]]=rank[sa[i-1]]+1;
    47         else
    48             rank[sa[i]]=rank[sa[i-1]];
    49     for(k=0;(1<<k)<=n;k++){
    50         sort(sa+1,sa+1+n,cmp);
    51         trank[sa[1]]=1;
    52         for(int i=2;i<=n;i++){
    53             if (rank[sa[i]]!=rank[sa[i-1]]||rank[sa[i]+(1<<k)]!=rank[sa[i-1]+(1<<k)])
    54                 trank[sa[i]]=trank[sa[i-1]]+1;
    55             else
    56                 trank[sa[i]]=trank[sa[i-1]];
    57         }
    58         for(int i=1;i<=n;i++)
    59             rank[i]=trank[i];
    60         if (rank[sa[n]]==n) break;
    61     }
    62     for(int i=1;i<=n;i++)
    63         rank[sa[i]]=i;
    64     ///height[i]表示sa[rank[i]]和sa[rank[i-1]]的最长前缀
    65     height[rank[1]]=0;
    66     for(int i=1;i<=n;i++){
    67         height[rank[i]]=max(height[rank[i-1]]-1,0);
    68         int p=i,q=sa[rank[i]-1];
    69         while (str[p+height[rank[i]]]==str[q+height[rank[i]]])
    70             height[rank[i]]++;
    71     }
    72     long long ans=0;
    73     for(int i=1;i<=n;i++)
    74         ans+=n-sa[i]-height[i];
    75       printf("%lld
    ",ans);
    76    return 0;
    77 }
    78 ///================fuction code====================
    Spoj 705

       尽量多做后缀数组的题目吧,熟能生巧,现在只是刚刚学会了后缀数组,还要多多加油才是。

     
  • 相关阅读:
    Python进程池multiprocessing.Pool的用法
    基于opencv的车牌提取项目
    Srapy 爬取知乎用户信息
    Scrapy框架简介及小项目应用
    豆瓣爬取图书标签
    CSS选择器使用
    关于 urlencode 的使用和 json 模块的介绍
    urllib库使用方法
    猫眼电影的各种爬取方法
    淘宝商品信息爬取
  • 原文地址:https://www.cnblogs.com/Houjikan/p/4379227.html
Copyright © 2011-2022 走看看