spoj-694-Distinct Substrings(后缀数组)
题意:
给定一个字符串,求不相同的子串的个数
分析:
每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同 的 前 缀 的 个 数 。
如 果 所 有 的 后 缀 按 照 suffix(sa[1]), suffix(sa[2]),suffix(sa[3]), ...... ,suffix(sa[n])的顺序计算,
不难发现,对于每一次新加进来的 后缀 suffix(sa[k]), 它将产生 n-sa[k] 个新 的前缀。
但 是其中有height[k]个是和前面的字符串的前缀是相同的。
所以 suffix(sa[k])将“贡献”出 n-sa[k]- height[k]个不同的子串。
累加后便是原问题的答案。这个做法的时间复杂度为 O(n)。
// File Name: 694.cpp
// Author: Zlbing
// Created Time: 2013年09月06日 星期五 13时34分31秒 #include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define CL(x,v); memset(x,v,sizeof(x));
#define INF 0x3f3f3f3f
#define LL long long
#define REP(i,r,n) for(int i=r;i<=n;i++)
#define RREP(i,n,r) for(int i=n;i>=r;i--)
//rank从0开始
//sa从1开始,因为最后一个字符(最小的)排在第0位
//height从2开始,因为表示的是sa[i-1]和sa[i]
const int MAXN=;
int rank[MAXN],sa[MAXN],X[MAXN],Y[MAXN],height[MAXN];
char s[MAXN];
int buc[MAXN];
void calheight(int n) {
int i , j , k = ;
for(i = ; i <= n ; i++) rank[sa[i]] = i;
for(i = ; i < n ; height[rank[i++]] = k)
for(k?k--: , j = sa[rank[i]-] ; s[i+k] == s[j+k] ; k++);
}
bool cmp(int *r,int a,int b,int l) {
return (r[a] == r[b] && r[a+l] == r[b+l]);
}
void suffix(int n,int m = ) {
int i , l , p , *x = X , *y = Y;
for(i = ; i < m ; i ++) buc[i] = ;
for(i = ; i < n ; i ++) buc[ x[i] = s[i] ] ++;
for(i = ; i < m ; i ++) buc[i] += buc[i-];
for(i = n - ; i >= ; i --) sa[ --buc[ x[i] ]] = i;
for(l = ,p = ; p < n ; m = p , l *= ) {
p = ;
for(i = n-l ; i < n ; i ++) y[p++] = i;
for(i = ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l;
for(i = ; i < m ; i ++) buc[i] = ;
for(i = ; i < n ; i ++) buc[ x[y[i]] ] ++;
for(i = ; i < m ; i ++) buc[i] += buc[i-];
for(i = n - ; i >= ; i --) sa[ --buc[ x[y[i]] ] ] = y[i];
for(swap(x,y) , x[sa[]] = , i = , p = ; i < n ; i ++)
x[ sa[i] ] = cmp(y,sa[i-],sa[i],l) ? p- : p++;
}
calheight(n-);//后缀数组关键是求出height,所以求sa的时候顺便把rank和height求出来
}
int solve(int n)
{
int ans=;
ans+=n-sa[];
for(int i=;i<=n;i++)
{
ans+=n-sa[i]-height[i];
}
return ans;
}
int main() {
int cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%s",s);
int n=strlen(s);
s[n]=;
suffix(n+);
int ans=solve(n);
printf("%d\n",ans);
}
return ;
}
spoj-694-Distinct Substrings(后缀数组)的更多相关文章
- spoj 694. Distinct Substrings 后缀数组求不同子串的个数
题目链接:http://www.spoj.com/problems/DISUBSTR/ 思路: 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数.如果所有的后缀按照su ...
- SPOJ - DISUBSTR Distinct Substrings (后缀数组)
Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...
- SPOJ DISUBSTR Distinct Substrings 后缀数组
题意:统计母串中包含多少不同的子串 然后这是09年论文<后缀数组——处理字符串的有力工具>中有介绍 公式如下: 原理就是加上新的,减去重的,这题是因为打多校才补的,只能说我是个垃圾 #in ...
- SPOJ 694. Distinct Substrings (后缀数组不相同的子串的个数)转
694. Distinct Substrings Problem code: DISUBSTR Given a string, we need to find the total number o ...
- SPOJ 694 Distinct Substrings/SPOJ 705 New Distinct Substrings(后缀数组)
Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...
- SPOJ 694 || 705 Distinct Substrings ( 后缀数组 && 不同子串的个数 )
题意 : 对于给出的串,输出其不同长度的子串的种类数 分析 : 有一个事实就是每一个子串必定是某一个后缀的前缀,换句话说就是每一个后缀的的每一个前缀都代表着一个子串,那么如何在这么多子串or后缀的前缀 ...
- SPOJ - SUBST1 New Distinct Substrings —— 后缀数组 单个字符串的子串个数
题目链接:https://vjudge.net/problem/SPOJ-SUBST1 SUBST1 - New Distinct Substrings #suffix-array-8 Given a ...
- 【SPOJ – SUBST1】New Distinct Substrings 后缀数组
New Distinct Substrings 题意 给出T个字符串,问每个字符串有多少个不同的子串. 思路 字符串所有子串,可以看做由所有后缀的前缀组成. 按照后缀排序,遍历后缀,每次新增的前缀就是 ...
- spoj Distinct Substrings 后缀数组
给定一个字符串,求不相同的子串的个数. 假如给字符串“ABA";排列的子串可能: A B A AB BA ABA 共3*(3+1)/2=6种; 后缀数组表示时: A ABA BA 对于A和 ...
- SPOJ 694 Distinct Substrings
Distinct Substrings Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on SPOJ. O ...
随机推荐
- [转] React同构思想
React比较吸引我的地方在于其客户端-服务端同构特性,服务端-客户端可复用组件,本文来简单介绍下这一架构思想. 出于篇幅原因,本文不会介绍React基础,所以,如果你还不清楚React的state/ ...
- Java基础知识强化之集合框架笔记19:List集合迭代器使用之 并发修改异常的产生原因 以及 解决方案
1. 我有一个集合,如下,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现. ConcurrentModi ...
- 【bzoj2938】[Poi2000]病毒
题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否 ...
- 9.23 noip模拟试题
Problem 1 抓牛(catchcow.cpp/c/pas) [题目描述] 农夫约翰被通知,他的一只奶牛逃逸了!所以他决定,马上出发,尽快把那只奶牛抓回来. 他们都站在数轴上.约翰在N(O≤N ...
- eclipse alt + '/' not working.
searching for google,I observed that the 'content assist' shortcut key was take placed with 'ctrl + ...
- hdoj 1087 (DP)
代码: #include<iostream> #include<cmath> using namespace std; int a[1005], dp[1005]; ...
- 从XML文件中获取格式化的文本信息
在FMW的运维过程中,时常需要将中间传输的XML信息转换为excel格式化的问题提交给关联系统人员,现总结三种格式化问题提供方式 一.使用Excel转换 因为从系统中取到的xml文档为中间信息文档,需 ...
- 【vc】1_Windows程序内部运行机制
创建一个Win32应用程序步骤: 1.编写WinMain函数; 2.创建窗口(步骤如下): a.设计(一个)窗口类(WNDCLASS) b.注册(该)窗口类. c.创建窗口. d.显示并更新窗口. 3 ...
- Linux 系统命令及其使用详解(大全)
(来源: 中国系统分析员) cat cd chmod chown cp cut 1.名称:cat 使用权限:所有使用者 使用方式:cat [-AbeEnstTuv] [--help] [--versi ...
- 实例:jQuery实现标签切换
具体实现效果如图: 原理很简单,就是监听鼠标滑动和点击事件.在第一个标签切换的示例中,当鼠标滑过某个标签时,就把class转移到当前标签.这里用到的jQuery方法主要是each()确定当前是哪一个标 ...