题意就是求一个字符串的重复出现(出现次数>=2)的不同子串的个数。

标准解法是后缀数组、最长公共前缀的应用,对于样例aabaab,先将所有后缀排序:

aab

3    aabaab

1    ab

2    abaab

0    b

1    baab

每个后缀前面数字代表这个后缀与它之前的后缀(rank比它小1)的最长公共前缀的长度:然而就可以这样理解这个最长公共前缀LCP、aabaab与aab的最长公共前缀是3,那说明子串a、aa、aab都至少出现的两次,那么这就是后缀aab重复出现的子串个数

然后我们考虑后缀ab与后缀aabaab的最长公共前缀=1,这时由于LCP(ab, aabaab) <= LCP(aabaab, aab),所以就说明ab与aabaab的所有公共前缀(只有LCP(ab, aabaab) = 1个)之前都已经计算过了,所以我们直接跳过

之后我们考虑后缀abaab与后缀ab的最长公共前缀LCP(abaab, ab) > LCP(ab, aabaab),同时,由于LCP(ab, aabaab) != 0,所以考虑abaab与ab的两个公共前缀(重复出现的子串)a、ab时,已经有了LCP(ab, aabaab) = 1个公共前缀(重复出现的子串)a已经计算过了,所以这时新的重复出现的子串的个数为LCP(abaab, ab) - LCP(ab, aabaab) = 1

最后总结起来就是:

    if(height[i] <= height[i - 1]) continue;

    if(height[i] > height[i - 1] ) ans += height[i] - height[i - 1]

这就是最后的答案。

 #include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf (-((LL)1<<40))
#define lson k<<1, L, (L + R)>>1
#define rson k<<1|1, ((L + R)>>1) + 1, R
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define rep(i, a, b) for(int i = a; i <= b; i ++)
#define dec(i, a, b) for(int i = a; i >= b; i --) template<class T> T CMP_MIN(T a, T b) { return a < b; }
template<class T> T CMP_MAX(T a, T b) { return a > b; }
template<class T> T MAX(T a, T b) { return a > b ? a : b; }
template<class T> T MIN(T a, T b) { return a < b ? a : b; }
template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b; } //typedef __int64 LL;
typedef long long LL;
const int MAXN = ;
const int MAXM = ;
const double eps = 1e-;
LL MOD = ; struct SufArray {
char s[MAXN];
int sa[MAXN], t[MAXN], t2[MAXN], c[MAXN], n, m;
int rnk[MAXN], height[MAXN];
int mi[MAXN][], idxK[MAXN]; void init() {
mem0(s);
mem0(height);
}
void read_str() {
gets(s);
m = ;
n = strlen(s);
s[n++] = ' ';
}
void build_sa() {
int *x = t, *y = t2;
rep (i, , m - ) c[i] = ;
rep (i, , n - ) c[x[i] = s[i]] ++;
rep (i, , m - ) c[i] += c[i - ];
dec (i, n - , ) sa[--c[x[i]]] = i;
for(int k = ; k <= n; k <<= ) {
int p = ;
rep (i, n - k, n - ) y[p++] = i;
rep (i, , n - ) if(sa[i] >= k) y[p++] = sa[i] - k;
rep (i, , m - ) c[i] = ;
rep (i, , n - ) c[x[y[i]]] ++;
rep (i, , m - ) c[i] += c[i - ];
dec (i, n - , ) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = ;
x[sa[]] = ;
rep (i, , n - ) {
x[sa[i]] = y[sa[i - ]] == y[sa[i]] && y[sa[i - ] + k] == y[sa[i] + k] ? p - : p++;
}
if(p >= n) break;
m = p;
}
}
void get_height() {
int k = ;
rep (i, , n - ) rnk[sa[i]] = i;
rep (i, , n - ) {
if(k) k --;
int j = sa[rnk[i] - ];
while(s[i + k] == s[j + k]) k ++;
height[rnk[i]] = k;
}
}
void rmq_init(int *a, int n) {
rep (i, , n - ) mi[i][] = a[i];
for(int j = ; ( << j) <= n; j ++) {
for(int i = ; i + (<<j) - < n; i ++) {
mi[i][j] = min(mi[i][j - ], mi[i + ( << (j - ))][j - ]);
}
}
rep (len, , n) {
idxK[len] = ;
while(( << (idxK[len] + )) <= len) idxK[len] ++;
}
}
int rmq_min(int l, int r) {
int len = r - l + , k = idxK[len];
return min(mi[l][k], mi[r - ( << k) + ][k]);
}
void lcp_init() {
get_height();
rmq_init(height, n);
}
int get_lcp(int a, int b) {
if(a == b) return n - a - ;
return rmq_min(min(rnk[a], rnk[b]) + , max(rnk[a], rnk[b]));
}
void solve() {
get_height();
LL ans = , pre = ;
rep (i, , n - ) {
if(height[i] > pre) ans += height[i] - pre;
pre = height[i];
}
cout << ans << endl;
}
}; int T;
SufArray sa; int main()
{
while(~scanf("%d%*c", &T)) while(T--){
sa.init();
sa.read_str();
sa.build_sa();
sa.solve();
}
return ;
}
/**************************************************************
Problem: 1632
User: csust_Rush
Language: C++
Result: Accepted
Time:880 ms
Memory:13192 kb
****************************************************************/

CSU1632Repeated Substrings(后缀数组/最长公共前缀)的更多相关文章

  1. POJ-2774-Long Long Message(后缀数组-最长公共子串)

    题意: 给定两个字符串 A 和 B,求最长公共子串. 分析: 字符串的任何一个子串都是这个字符串的某个后缀的前缀. 求 A 和 B 的最长公共子串等价于求 A 的后缀和 B 的后缀的最长公共前缀的最大 ...

  2. POJ3415 Common Substrings —— 后缀数组 + 单调栈 公共子串个数

    题目链接:https://vjudge.net/problem/POJ-3415 Common Substrings Time Limit: 5000MS   Memory Limit: 65536K ...

  3. POJ 2217 (后缀数组+最长公共子串)

    题目链接: http://poj.org/problem?id=2217 题目大意: 求两个串的最长公共子串,注意子串是连续的,而子序列可以不连续. 解题思路: 后缀数组解法是这类问题的模板解法. 对 ...

  4. [poj 2274]后缀数组+最长公共子串

    题目链接:http://poj.org/problem?id=2774 后缀数组真的太强大了,原本dp是O(nm)的复杂度,在这里只需要O(n+m). 做法:将两个串中间夹一个未出现过的字符接起来,然 ...

  5. POJ3450 Corporate Identity —— 后缀数组 最长公共子序列

    题目链接:https://vjudge.net/problem/POJ-3450 Corporate Identity Time Limit: 3000MS   Memory Limit: 65536 ...

  6. POJ3294 Life Forms —— 后缀数组 最长公共子串

    题目链接:https://vjudge.net/problem/POJ-3294 Life Forms Time Limit: 5000MS   Memory Limit: 65536K Total ...

  7. POJ 2774 (后缀数组 最长公共字串) Long Long Message

    用一个特殊字符将两个字符串连接起来,然后找最大的height,而且要求这两个相邻的后缀的第一个字符不能在同一个字符串中. #include <cstdio> #include <cs ...

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

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

  9. POJ1226:Substrings(后缀数组)

    Description You are given a number of case-sensitive strings of alphabetic characters, find the larg ...

随机推荐

  1. centos下搭建DNS

    一.DNS名词介绍: ( Domain Name System )是“域名系统”的英文缩写 正向解析:通过域名查找IP 反向解析:通过IP查找域名 二.安装BIND: BIND即Berkeley In ...

  2. Android------底部导航栏BottomNavigationBar

    Android 的底部导航栏 BottomNavigationBar 由Google官方Material design中增加的. Android底部导航栏的实现方式特别多,例如TabHost,TabL ...

  3. HQL查询中取个别几个字段

    数据表:

  4. Linux下记录所有用户的登录和操作日志

    Linux下记录所有用户的登录和操作日志   一般我们可以用history命令来查看用户的操作记录,但是这个命令不能记录是哪个用户登录操作的,也不能记录详细的操作时间,且不完整:所以误操作而造成重要的 ...

  5. ExcelHelper.cs

    using System; using System.IO; using System.Data; using System.Collections; using System.Data.OleDb; ...

  6. LA3029

    题解: 一个类似尺取法的算法 代码: #include<cstdio> #include<algorithm> using namespace std; ; int T,n,m ...

  7. PHP回调函数call_user_func()和call_user_func_array()的使用

    call_user_func():把第一个参数作为回调函数调用 用法:call_user_func ( callable $callback [, mixed $parameter [, mixed ...

  8. 字符串比较,栈溢出引起的程序bug

    需求 输入密码字符串,与设定的密码“1234567”进行比较,两者相符则输出"congratulations!”,不符则输出“try again!”. 程序bug 实际运行过程中发现,输入某 ...

  9. 《Effective C++》第5章 实现-读书笔记

    章节回顾: <Effective C++>第1章 让自己习惯C++-读书笔记 <Effective C++>第2章 构造/析构/赋值运算(1)-读书笔记 <Effecti ...

  10. MoreEffectiveC++Item35(效率)(条款16-24)

    条款16 谨记80-20法则 条款17 考虑使用 lazy evaluation(缓释评估) 条款18 分期摊还预期的计算成本 条款19 了解临时对象的来源 条款20 协助完成"返回值的优化 ...