题意

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

思路

一个字符串的子串都必然是它的某个后缀的前缀。对于每一个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. C# 获取计算机cpu 硬盘 网卡信息

    /// <summary>/// 机器码         /// </summary>       public class MachineCode         {     ...

  2. java获得两个日期之间的所有月份

    private static List<String> getMonthBetween(String minDate, String maxDate) throws ParseExcept ...

  3. path.resolve()和path.join()

    resolve 作用:path.resolve() 该方法将一些的 路径/路径段 解析为绝对路径. 语法:path.resolve([...paths]) 说明: ...paths <strin ...

  4. 在python3下使用OpenCV做离散余弦变换DCT及其反变换IDCT

    对图像处理经常用到DCT, Python下有很多带有DCT算法包, 这里使用OpenCV的DCT做变换, 并简单置0部分数据, 再查看反变换图像的效果. import numpy as np impo ...

  5. JAVA学习笔记之图解JAVA参数传递

    今天做项目,发现了一个问题,当String作为参数传递的时候,在函数内部改变值对外部的变量值无影响,如下代码: public static void main(String[] args) { Str ...

  6. hadoop namenode HA集群搭建

    hadoop集群搭建(namenode是单点的)  http://www.cnblogs.com/kisf/p/7456290.html HA集群需要zk, zk搭建:http://www.cnblo ...

  7. 20145331 实验一 "Java开发环境的熟悉"

    20145331 实验一 "Java开发环境的熟悉" 实验内容 使用JDK和IDE编译.运行简单的Java程序.题目: 实现四则运算,并进行测试. 编写代码 1.首先第一步就是要输 ...

  8. 20144303 《Java程序设计》课程总结

    20144303 <Java程序设计>课程总结 每周读书笔记链接汇总 第一周:http://www.cnblogs.com/20144303sys/p/5248979.html 第二周:h ...

  9. Kali视频学习6-10

    Kali视频学习6-10 kali信息收集之主机探测 主机探测指识别目标机器是否可用(简单来说是否在线),在探测过程中,需要得到目标是否online等信息.由于IDS和(入侵检测系统)和IPS(入侵保 ...

  10. Job流程:决定map个数的因素

    此文紧接Job流程:提交MR-Job过程.上一篇分析可以看出,MR-Job提交过程的核心代码在于 JobSubmitter 类的 submitJobInternal()方法.本文就由此方法的这一句代码 ...