spoj 694 Distinct Substrings(后缀数组)

题目:求一个字符串中所有不同子串个数

后缀数组经典题,每一个子串一定是某个后缀的前缀,那么问题便等价于求所有后缀之间的不相同的前缀个数。我们按sa的顺序来考虑,当加入sa[k]的时候,sa[k]这个后缀的长度为n-sa[k]-1,那么便有n-sa[k]-1个前缀,但是由heigh数组可知sa[k]与sa[k-1]有height[k]个前缀是相同的,所以要除去。

注意的是这道题题意有点坑,一开始以为字母只能是大写的而且长度在1000之内,可发现根本不是这样!!!!!!!!最后改了m的值又把数组开到了50000才ac。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#define eps 1e-6
#define LL long long
using namespace std;  

const int maxn = 50005;
//const int INF = 0x3f3f3f3f;
char str[maxn];

struct SuffixArray {  

    int s[maxn];      /// 原始字符数组(最后一个字符应必须是0,而前面的字符必须非0)
    int sa[maxn];     // 后缀数组,sa[0]一定是n-1,即最后一个字符
    int rank[maxn];   // 名次数组
    int height[maxn]; // height数组
    int t[maxn], t2[maxn], c[maxn]; // 辅助数组
    int n; // 字符个数  

    void clear() { n = 0; memset(sa, 0, sizeof(sa)); }  

    /// m为最大字符值加1。!!! 调用之前需设置好s和n
    void build_sa(int m) {
 	   int i, *x = t, *y = t2;
    	for(i = 0; i < m; i++) c[i] = 0;
	    for(i = 0; i < n; i++) c[x[i] = s[i]]++;
    	for(i = 1; i < m; i++) c[i] += c[i-1];
	    for(i = n-1; i >= 0; i--) sa[--c[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++) c[i] = 0;
      		for(i = 0; i < n; i++) c[x[y[i]]]++;
      		for(i = 0; i < m; i++) c[i] += c[i-1];
      		for(i = n-1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i];
      		swap(x, y);
      		p = 1; x[sa[0]] = 0;
      		for(i = 1; i < n; i++)
      			x[sa[i]] = y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k] ? p-1 : p++;
      		if(p >= n) break;
      		m = p;
    	}
  	}  

    void build_height() {
    	int i, j, k = 0;
    	for(i = 0; i < n; i++) rank[sa[i]] = i;
    	for(i = 0; i < n; i++) {
        	if(k) k--;
      		j = sa[rank[i]-1];
      		while(s[i+k] == s[j+k]) k++;
      		height[rank[i]] = k;
    	}
  	}
} sa;

void init() {
	sa.clear();
	cin >> str;
	int len = strlen(str);
	for(int i = 0; i < len; i++) sa.s[i] = str[i] - 'A' + 1;
	sa.s[len] = 0;
	sa.n = len + 1;
}

void solve() {
	sa.build_sa(300);
	sa.build_height();
	int ans = sa.n - sa.sa[1] - 1;
	for(int i = 2; i < sa.n; i++) ans += sa.n - 1 - sa.sa[i] - sa.height[i];
	cout << ans << endl;
}

int main() {
	//freopen("input.txt", "r", stdin);
	int t; cin >> t;
	while(t--) {
		init();
		solve();
	}
	return 0;
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-28 20:27:12

spoj 694 Distinct Substrings(后缀数组)的相关文章

spoj 694 Distinct Substrings 后缀数组

题目链接 求一个字符串中不相同的子串的个数. 子串的总数是(n+1)*n/2, 减去height[i]就可以. #include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include

SPOJ 694、705 后缀数组:求不同子串

思路:这题和wikioi 1306一样,也都是求的不同子串的个数,但是wikioi 时间比较长,然后用Trie树就过了.但是我用那个代码提交这题的时候就WA了,比较晕--因为这题有多组样例,所以超了点时间. 所以这题当然就是用后缀数组做的啦! 算法分析: 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数.如果所有的后缀按照suffix(sa[1]),suffix(sa[2]),suffix(sa[3]),--,suffix(sa[n])的顺序计算,不难发现,对于每

SPOJ 694. Distinct Substrings,705. New Distinct Substrings(后缀数组)

题目大意:给定长度为N的字符串,求出其中不相同子串的个数. 解题思路:每一个字串一定是某个后缀的前缀,那么原问题就可以等价于求所有后缀之间的不相同的前缀的个数.如果所有的后缀按照suffix(sa[1]),suffix(sa[2])--suffix(sa[n])的顺序计算,我们会发现对于每个新加进来的后缀suffix(sa[k]),它将产生n-sa[k]+1个新的前缀.但是其中有leight[k]个是和前面的字符串的前缀是相同的.所以suffix(sa[k])加进来增加的不同的子串的个数为n-s

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

题意 : 对于给出的串,输出其不同长度的子串的种类数 分析 : 有一个事实就是每一个子串必定是某一个后缀的前缀,换句话说就是每一个后缀的的每一个前缀都代表着一个子串,那么如何在这么多子串or后缀的前缀中找出不同的并计数呢?思路就是所有的可能子串数 - 重复的子串数.首先我们容易得到一个长度为 len 的串的子串数为 len * ( len + 1) / 2.那如何知道重复的子串数呢?答案就是利用后缀数组去跑一遍 Height ,得到所有的最长公共前缀(LCP),这些最长公共前缀的值都存在了 He

spoj Distinct Substrings 后缀数组

给定一个字符串,求不相同的子串的个数. 假如给字符串“ABA";排列的子串可能: A B A AB  BA ABA 共3*(3+1)/2=6种; 后缀数组表示时: A ABA BA 对于A和AB height[i]=1; 表明一个长度公共,所以ABA中多出现了A这个子串,所以6-1=5: 对于ABA BA height[i]=0,所以不需要减去. 最后答案为5: #include<iostream> #include<stdio.h> #include<string

SPOJ694&amp;&amp;SPOJ705:Distinct Substrings(后缀数组)

Description 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 numb

SPOJ694--- DISUBSTR - Distinct Substrings(后缀数组)

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 distin

Spoj 694 Distinct Substrings

Given a string, we need to find the total number of its distinct substrings. 给你一个字符中,统计有多少个不同的子串InputT- number of test cases. T<=20;Each test case consists of one string, whose length is <= 1000OutputFor each test case output one number saying the n

后缀数组 SPOJ 694 Distinct Substrings

题目链接 题意:给定一个字符串,求不相同的子串的个数 分析:我们能知道后缀之间相同的前缀的长度,如果所有的后缀按照 suffix(sa[0]), suffix(sa[1]), suffix(sa[2]), …… ,suffix(sa[n])的顺序计算,不难发现,对于每一次新加进来的后缀 suffix(sa[k]),它将产生 n-sa[k]+1 个新的前缀.但是其中有 height[k]个是和前面的字符串的前缀是相同的.所以 suffix(sa[k])将“贡献” 出 n-sa[k]+1- heig