DISUBSTR - Distinct Substrings

no tags 

Given a string, we need to find the total number of its distinct substrings.

Input

T- number of test cases. T<=20;
Each test case consists of one string, whose length is <= 1000

Output

For each test case output one number saying the number of distinct substrings.

Example

Sample Input:
2
CCCCC
ABABA

Sample Output:
5
9

Explanation for the testcase with string ABABA: 
len=1 : A,B
len=2 : AB,BA
len=3 : ABA,BAB
len=4 : ABAB,BABA
len=5 : ABABA
Thus, total number of distinct substrings is 9.

 

题目链接:SPOJ DISUBSTR

一开始想用字典树,结果静态建树的Trie超时了(懒的写动态指针版……)真相是用后缀数组做的,因为每一个后缀的贡献原本为其长度,原本总贡献为$(len + 1) * len / 2$,但由于一些串重复,我们要减掉,再想一想,这些重复的是后缀的前缀,也就是$Suffix(x)$和$Suffix(y)$的公共前缀$LCP(x,y)$,但是x与y如何确定才能准确不遗漏地算出这些重复的串呢?按字典序排,然后height数组就是基于字典序排序的后缀,因此把所有height值减掉就好了。不过似乎有人用指针写的Trie过了,果然指针除了爆内存的风险,速度确实快啊。

想了一下用后缀数组只要$O(Nlog_{2}N)$,而字典树至少$O(N*N)$,果然不是一个档次……

代码:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <bitset>
#include <string>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define fin(name) freopen(name,"r",stdin)
#define fout(name) freopen(name,"w",stdout)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 1010;
int wa[N], wb[N], cnt[N], sa[N];
int ran[N], height[N];
char s[N]; inline int cmp(int r[], int a, int b, int d)
{
return r[a] == r[b] && r[a + d] == r[b + d];
}
void DA(int n, int m)
{
int i;
int *x = wa, *y = wb;
for (i = 0; i < m; ++i)
cnt[i] = 0;
for (i = 0; i < n; ++i)
++cnt[x[i] = s[i]];
for (i = 1; i < m; ++i)
cnt[i] += cnt[i - 1];
for (i = n - 1; i >= 0; --i)
sa[--cnt[x[i]]] = i;
for (int k = 1; k <= n; k <<= 1)
{
int p = 0;
for (i = n - k; i < n; ++i)
y[p++] = i;
for (i = 0; i < n; ++i)
if (sa[i] >= k)
y[p++] = sa[i] - k;
for (i = 0; i < m; ++i)
cnt[i] = 0;
for (i = 0; i < n; ++i)
++cnt[x[y[i]]];
for (i = 1; i < m; ++i)
cnt[i] += cnt[i - 1];
for (i = n - 1; i >= 0; --i)
sa[--cnt[x[y[i]]]] = y[i];
swap(x, y);
x[sa[0]] = 0;
p = 1;
for (i = 1; i < n; ++i)
x[sa[i]] = cmp(y, sa[i - 1], sa[i], k) ? p - 1 : p++;
m = p;
if (p >= n)
break;
}
}
void getght(int n)
{
int i, k = 0;
for (i = 1; i <= n; ++i)
ran[sa[i]] = i;
for (i = 0; i < n; ++i)
{
if (k)
--k;
int j = sa[ran[i] - 1];
while (s[i + k] == s[j + k])
++k;
height[ran[i]] = k;
}
}
int main(void)
{
int T, i;
scanf("%d", &T);
while (T--)
{
scanf("%s", s);
int len = strlen(s);
DA(len + 1, *max_element(s, s + len) + 1);
getght(len);
int ans = (len + 1) * len >> 1;
for (i = 1; i <= len; ++i)
ans -= height[i];
printf("%d\n", ans);
}
return 0;
}

SPOJ Distinct Substrings(后缀数组求不同子串个数,好题)的更多相关文章

  1. spoj 694. Distinct Substrings 后缀数组求不同子串的个数

    题目链接:http://www.spoj.com/problems/DISUBSTR/ 思路: 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数.如果所有的后缀按照su ...

  2. spoj Distinct Substrings 后缀数组

    给定一个字符串,求不相同的子串的个数. 假如给字符串“ABA";排列的子串可能: A B A AB  BA ABA 共3*(3+1)/2=6种; 后缀数组表示时: A ABA BA 对于A和 ...

  3. SPOJ(后缀数组求不同子串个数)

    DISUBSTR - Distinct Substrings Given a string, we need to find the total number of its distinct subs ...

  4. SPOJ - SUBST1 New Distinct Substrings —— 后缀数组 单个字符串的子串个数

    题目链接:https://vjudge.net/problem/SPOJ-SUBST1 SUBST1 - New Distinct Substrings #suffix-array-8 Given a ...

  5. SPOJ 694 || 705 Distinct Substrings ( 后缀数组 && 不同子串的个数 )

    题意 : 对于给出的串,输出其不同长度的子串的种类数 分析 : 有一个事实就是每一个子串必定是某一个后缀的前缀,换句话说就是每一个后缀的的每一个前缀都代表着一个子串,那么如何在这么多子串or后缀的前缀 ...

  6. SPOJ SUBST1 New Distinct Substrings(后缀数组 本质不同子串个数)题解

    题意: 问给定串有多少本质不同的子串? 思路: 子串必是某一后缀的前缀,假如是某一后缀\(sa[k]\),那么会有\(n - sa[k] + 1\)个前缀,但是其中有\(height[k]\)个和上一 ...

  7. SPOJ - DISUBSTR Distinct Substrings (后缀数组)

    Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...

  8. 【SPOJ – SUBST1】New Distinct Substrings 后缀数组

    New Distinct Substrings 题意 给出T个字符串,问每个字符串有多少个不同的子串. 思路 字符串所有子串,可以看做由所有后缀的前缀组成. 按照后缀排序,遍历后缀,每次新增的前缀就是 ...

  9. SPOJ DISUBSTR Distinct Substrings 后缀数组

    题意:统计母串中包含多少不同的子串 然后这是09年论文<后缀数组——处理字符串的有力工具>中有介绍 公式如下: 原理就是加上新的,减去重的,这题是因为打多校才补的,只能说我是个垃圾 #in ...

随机推荐

  1. webpack和sass功能简介

    1.webpack webpack 是一个打包工具,为什么需要打包?因为有的人的脚本开发语言可能是 CoffeeScript 或者是 TypeScript,样式开发工具可能是 Less 或者 Sass ...

  2. PHP接收http请求头信息

    1.PHP 自带函数 getallheaders() 目前 getallheaders() 只能用于 apache 中.如果想在 nginx 中也能使用,可以使用自定义函数. foreach (get ...

  3. VSCode插件整理

    VSCode插件整理 VSCode插件整理 官网地址 vscode常用配置(User Settings文件) 基本插件 前端插件 VUE部分 python MarkDown部分 连接Linux 本地与 ...

  4. zabbix配置报警媒介-用户-动作-邮件脚本触发mailx邮件报警

    2018-09-16更新,新版本zabbix不需要使用脚本发送邮件,在zabbix web界面直接配置就可以 配置邮件参数,测试发送邮件 确认安装相关服务,centos7默认安装 [root@VM_1 ...

  5. Go web表单验证

    开发Web的一个原则就是,不能信任用户输入的任何信息,所以验证和过滤用户的输入信息就变得非常重要 必填字段 if len(r.Form["username"][0])==0{ // ...

  6. JAVA 泛型方法<T>

    public static void main(String[] args) throws Exception { String[] arr = new String[]{"1", ...

  7. HBase配置和使用

    参考官方文档 整体实现框架 图1 以下几个为组成部件 21892 HMaster 22028 HRegionServer 21553 QuorumPeerMain 2366 NameNode 2539 ...

  8. BFS 队列

    Plague Inc. is a famous game, which player develop virus to ruin the world. JSZKC wants to model thi ...

  9. shell eval命令使用

    eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令. 该命令适用于那些一次扫描无法实现其功能的变量.该命令对变量进行两次扫描. 这些需要进行两次扫描的变量有时被称为复杂变量.不过这些变量本 ...

  10. web框架与爬虫

    所有的web框架 http://www.cnblogs.com/wupeiqi/articles/5341480.html 爬虫技术 http://www.cnblogs.com/wupeiqi/ar ...