题意

给定一个字符串,求它的所有不重复子串的个数

思路

一个字符串的子串都必然是它的某个后缀的前缀。对于每一个sa[i]后缀,它的起始位置sa[i],那么它最多能得到该后缀长度个子串(n-sa[i]个),而其中有height[i]个是与前一个后缀相同的,所以它能产生的实际后缀个数便是n-sa[i]-height[i]。遍历一次所有的后缀,将它产生的后缀数加起来便是答案。

代码

[cpp]
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
#define MID(x,y) ((x+y)/2)
#define MEM(a,b) memset(a,b,sizeof(a))
using namespace std;

//Suffix Array
const int maxn = 1005;
int wx[maxn], wy[maxn], wxy[maxn], hs[maxn];
int r[maxn], sa[maxn], ranks[maxn], height[maxn];
int cmp(int r[], int a, int b, int l){
return (r[a] == r[b] && r[a+l] == r[b+l]);
}
//r is the string, and r[n-1] = 0, this means we should add a '0' at the end of the string.
void da(int r[], int sa[], int ranks[], int height[], int n, int m){
//calculate sa[], begin at 1 because sa[0] = "0".
int i, j, len, p, k = 0, *x = wx, *y = wy, *t;
for (i = 0; i < m; i ++) hs[i] = 0;
for (i = 0; i < n; i ++) hs[x[i] = r[i]] ++;
for (i = 1; i < m; i ++) hs[i] += hs[i-1];
for (i = n-1; i >= 0; i --) sa[-- hs[x[i]]] = i;
for (len = 1, p = 1; p < n; len *= 2, m = p){
for (p = 0, i = n - len; i < n; i ++) y[p ++] = i;
for (i = 0; i < n; i ++) if (sa[i] >= len) y[p ++] = sa[i] - len;
for (i = 0; i < n; i ++) wxy[i] = x[y[i]];
for (i = 0; i < m; i ++) hs[i] = 0;
for (i = 0; i < n; i ++) hs[wxy[i]] ++;
for (i = 1; i < m; i ++) hs[i] += hs[i-1];
for (i = n-1; i >= 0; i --) sa[-- hs[wxy[i]]] = y[i];
for (t = x, x = y, y = t, p = 1, i = 1, x[sa[0]] = 0; i < n; i ++)
x[sa[i]] = cmp(y, sa[i-1], sa[i], len)?p-1:p ++;
}
//calculate height[], height[n-1] is null because we add a '0' at the end of the string.
for (i = 1; i < n; i ++) ranks[sa[i]] = i;
for (i = 0; i < n - 1; height[ranks[i++]] = k)
for (k?k--:0, j = sa[ranks[i]-1]; r[i+k] == r[j+k]; k ++);
}

int main(){
//freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
int t;
scanf("%d", &t);
while(t --){
char tmps[1005] = {0};
scanf("%s", tmps);
MEM(r, 0);
int n = strlen(tmps);
for (int i = 0; i < n; i ++) r[i] = tmps[i];
da(r, sa, ranks, height, n + 1, 100);
int res = 0;
for (int i = 1; i <= n; i ++){
res += n - sa[i] - height[i];
}
printf("%d\n", res);
}
return 0;
}
[/cpp]

SPOJ 694 && SPOJ 705 (不重复子串个数:后缀数组)的更多相关文章

  1. POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)+后缀数组模板

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7586   Accepted: 3448 Cas ...

  2. cogs1709. [SPOJ 705] 不同的子串(后缀数组

    http://cogs.pro:8080/cogs/problem/problem.php?pid=vyziQkWaP 题意:给定一个字符串,计算其不同的子串个数. 思路:ans=总共子串个数-相同的 ...

  3. POJ 3261 可重叠的 k 次最长重复子串【后缀数组】

    这也是一道例题 给定一个字符串,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠.算法分析:这题的做法和上一题差不多,也是先二分答案,然后将后缀分成若干组.不同的是,这里要判断的是有没有一个组 ...

  4. POJ1743 Musical Theme 最长重复子串 利用后缀数组

    POJ1743 题目意思是求不重叠的最长相同变化的子串,输出该长度 比如1 2 3 4 5 6 7 8 9 10,最长长度为5,因为子串1 2 3 4 5 和 6 7 8 9 10变化都一样的 思路: ...

  5. 【poj3693-重复次数最多的连续重复子串】后缀数组

    题意:给定一个串,长度<=10^5,求它重复次数最多的连续重复子串(输出字典序最小的那个). 例如ccabcabc,答案就是abcabc 一开始没想清楚,结果调了好久. 原理: 按照L划分,因为 ...

  6. 洛谷P2408 不同子串个数 后缀数组 + Height数组

    ## 题目描述: 给你一个长为 $N$ $(N<=10^5)$ 的字符串,求不同的子串的个数我们定义两个子串不同,当且仅当有这两个子串长度不一样 或者长度一样且有任意一位不一样.子串的定义:原字 ...

  7. LUOGU P2408 不同子串个数(后缀数组)

    传送门 解题思路 后缀数组求本质不同串的裸题.\(ans=\dfrac{n(n+1)}{2} -\sum height[i]\). 代码 #include<iostream> #inclu ...

  8. ACdream 1430——SETI——————【后缀数组,不重叠重复子串个数】

    SETI Time Limit: 4000/2000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) Submit Statist ...

  9. 【SPOJ】Distinct Substrings/New Distinct Substrings(后缀数组)

    [SPOJ]Distinct Substrings/New Distinct Substrings(后缀数组) 题面 Vjudge1 Vjudge2 题解 要求的是串的不同的子串个数 两道一模一样的题 ...

随机推荐

  1. Objective-C中的alloc和init问题

    从开始学的NSString *name=[[NSString alloc] init] 起,仅仅这句话是分配内存空间,一直在用,从来没考虑过它的内部是怎么实现的.今天无意中看到了这一句代码: NSSt ...

  2. Vue组件的定义方式

    1.使用template标签定义组件 <!DOCTYPE html> <html> <head> <meta charset="UTF-8" ...

  3. v9上传图片/附件失败出现undefined的解决方法之一

    把phpcms\modules\attachment\attachments.php中将                        if(empty($this->userid)){改成  ...

  4. ruby中的顶层方法

    在ruby中写顶层函数的时候,总会有一个问题,self是谁,这些方法是谁的,是什么方法. 如下: p self p self.class def talk p self end talk 输出main ...

  5. SSH的加入顺序*(转)

    首先创建一个 New  =>  Web Project  起名 demo 然后在项目名称上 点击鼠标右键 选择 MyEclipse => Add Speing Capabilites... ...

  6. FileOutputStream写出数据实现换行和追加写入

    FileOutputStream fos = fos = new FileOutputStream(Utils.getData(bizCtx,"strcat(getenv(HWORKDIR) ...

  7. xlrd的使用操作

    # _*_ coding:utf-8 _*_ #---------------------------------------------------------------------------- ...

  8. 20145328 《Java程序设计》实验五实验报告

    20145328 <Java程序设计>实验五实验报告 实验名称 Java网络编程 实验内容 用书上的TCP代码,实现服务器与客户端. 客户端与服务器连接 客户端中输入明文,利用DES算法加 ...

  9. 如何为openwrt中的某个模块生成PKG_MIRROR_HASH

    答:介绍两种方法,第一种自动生成(当然使用自动的啦),第二种手动生成 第一种方法: 1.在软件包的Makefile中让此项写成这样PKG_MIRROR_HASH:=skip  (如果不加上skip,那 ...

  10. Response attachment filename 中文乱码

    Response.setHeader("Content-Disposition", "attachment; filename=" + fileName+&qu ...