【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]
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <ctime>
#include <functional>
#define pritnf printf
#define scafn scanf
#define sacnf scanf
#define For(i,j,k) for(int i=(j);i<=(k);(i)++)
#define Clear(a) memset(a,0,sizeof(a))
using namespace std;
typedef unsigned int Uint;
const int INF=0x3fffffff;
const double eps=1e-;
///==============struct declaration============== ///==============var declaration=================
const int MAXN=;
int n,k;
int sa[MAXN],rank[MAXN],h[MAXN],trank[MAXN],height[MAXN];
char str[MAXN];
///==============function declaration============
bool cmp(int a,int b){return rank[a]==rank[b]?rank[a+(<<k)]<rank[b+(<<k)]:rank[a]<rank[b];}
bool cmp1(int a,int b){return str[a]<str[b];}
///==============main code=======================
int main()
{
scanf("%s",str+);
n=strlen(str+);str[n+]='$';n++;
for(int i=;i<=n;i++)
sa[i]=i;
sort(sa+,sa++n,cmp1);
rank[sa[]]=;
for(int i=;i<=n;i++)
if (str[sa[i]]!=str[sa[i-]])
rank[sa[i]]=rank[sa[i-]]+;
else
rank[sa[i]]=rank[sa[i-]];
for(k=;(<<k)<=n;k++){
sort(sa+,sa++n,cmp);
trank[sa[]]=;
for(int i=;i<=n;i++){
if (rank[sa[i]]!=rank[sa[i-]]||rank[sa[i]+(<<k)]!=rank[sa[i-]+(<<k)])
trank[sa[i]]=trank[sa[i-]]+;
else
trank[sa[i]]=trank[sa[i-]];
}
for(int i=;i<=n;i++)
rank[i]=trank[i];
if (rank[sa[n]]==n) break;
}
for(int i=;i<=n;i++)
rank[sa[i]]=i;
///height[i]表示sa[rank[i]]和sa[rank[i-1]]的最长前缀
height[rank[]]=;
for(int i=;i<=n;i++){
height[rank[i]]=max(height[rank[i-]]-,);
int p=i,q=sa[rank[i]-];
while (str[p+height[rank[i]]]==str[q+height[rank[i]]])
height[rank[i]]++;
}
long long ans=;
for(int i=;i<=n;i++)
ans+=n-sa[i]-height[i];
printf("%lld\n",ans);
return ;
}
///================fuction code====================
Spoj 705
尽量多做后缀数组的题目吧,熟能生巧,现在只是刚刚学会了后缀数组,还要多多加油才是。
【spoj705】 Distinct Substrings的更多相关文章
- 【SPOJ】Distinct Substrings(后缀自动机)
[SPOJ]Distinct Substrings(后缀自动机) 题面 Vjudge 题意:求一个串的不同子串的数量 题解 对于这个串构建后缀自动机之后 我们知道每个串出现的次数就是\(right/e ...
- 【SPOJ】Distinct Substrings/New Distinct Substrings(后缀数组)
[SPOJ]Distinct Substrings/New Distinct Substrings(后缀数组) 题面 Vjudge1 Vjudge2 题解 要求的是串的不同的子串个数 两道一模一样的题 ...
- 【SPOJ】Distinct Substrings
[SPOJ]Distinct Substrings 求不同子串数量 统计每个点有效的字符串数量(第一次出现的) \(\sum\limits_{now=1}^{nod}now.longest-paren ...
- 【SPOJ694】Distinct Substrings (SA)
求不相同子串个数 该问题等价于求所有后缀间不相同前缀的个数..也就是对于每个后缀suffix(sa[i]),将贡献出n-sa[i]+1个,但同时,要减去那些重复的,即为height[i],故答案 ...
- 【CF316G3】Good Substrings 后缀自动机
[CF316G3]Good Substrings 题意:给出n个限制(p,l,r),我们称一个字符串满足一个限制当且仅当这个字符串在p中的出现次数在[l,r]之间.现在想问你S的所有本质不同的子串中, ...
- 【SPOJ 694】Distinct Substrings (更直接的求法)
[链接]h在这里写链接 [题意] 接上一篇文章 [题解] 一个字符串所有不同的子串的个数=∑(len-sa[i]-height[i]) [错的次数] 0 [反思] 在这了写反思 [代码] #inclu ...
- 【SPOJ 694】Distinct Substrings
[链接]h在这里写链接 [题意] 给你一个长度最多为1000的字符串 让你求出一个数x,这个x=这个字符串的不同子串个数; [题解] 后缀数组题. 把原串复制一份,加在 ...
- 【UVA10829】 L-Gap Substrings (后缀数组)
Description If a string is in the form UVU, where U is not empty, and V has exactly L characters, we ...
- 【POJ3415】 Common Substrings(后缀数组|SAM)
Common Substrings Description A substring of a string T is defined as: T(i, k)=TiTi+1...Ti+k-1, 1≤i≤ ...
随机推荐
- [LeetCode] Ugly Number II 丑陋数之二
Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime factors ...
- 用jQuery获取表单的值
在日常开发过程中,有许多用到表单的地方.比如登录,注册,比如支付,填写订单,比如后台管理等等. 使用jQuery来获取表单的值是比较常见的做法. 常见表单 单行文字域:<input type=' ...
- websocket初探
本文尚未完成,在此只写一些句子,以后慢慢整理. 一.参数 IllegalArgumentException No payload parameter present on the method[mes ...
- 【C#】安装windows服务
参考:http://blog.csdn.net ,http://blog.csdn.net/dyzcode 1.新建 visual studio insaller 项目2.添加 [文件系统]3.添加 ...
- [转]Excel导入异常Cannot get a text value from a numeric cell解决
原文地址:http://blog.csdn.net/ysughw/article/details/9288307 POI操作Excel时偶尔会出现Cannot get a text value fro ...
- C#中Abstract和Virtual的区别
c# 中 Abstract和Virtual比较容易混淆,都与继承有关,并且涉及override的使用.下面讨论一下二者的区别: 一.Virtual方法(虚方法) virtual 关键字用于在基类中修饰 ...
- sql语句-备忘
-- 清空全部数据,不写日志,不可恢复,速度极快truncate table 表名; -- 清空全部数据,写日志,数据可恢复,速度慢delete from 表名; --从一个数据库复制一张表带另一 ...
- C++ namespace
namespace, 命名空间, 用于解决命名冲突的问题. Python中的package/module, Javascript中的object, Java中的package都具有这样的功能. 如何使 ...
- 【配置】检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法(非简单设置为【经典】模式)。
× 检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法(非简单设置为[经典]模式). 我们将ASP.NET程序从IIS6移植到IIS7,可能运行提示以下错误: HTTP 错误 5 ...
- Android笔记
SYSTEM_ALERT_WINDOW and WRITE_SETTINGS, 这两个权限比较特殊,不能通过代码申请方式获取,必须得用户打开软件设置页手动打开,才能授权.路径是:Settings-&g ...