CF原题(http://codeforces.com/blog/entry/4849, 204E), CF的解法是O(Nlog^2N)的..记某个字符串以第i位开头的字符串对答案的贡献f(i), 那么f(i-1)>=f(i)-1, 然后就是O(NlogN)了, 但是速度垫底了....被后缀自动机完爆了...

----------------------------------------------------------------------------------------------

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
typedef long long ll;
#define b(x) (1 << (x))
 
const int maxn = 200009;
 
int Sa[maxn], Rank[maxn], Height[maxn], S[maxn], cnt[maxn];
int L[maxn], R[maxn], Id[maxn]; // [L, R)
int buf[20], Pos[maxn], mn[20][maxn], K, N, n;
char str[maxn];
 
void Init() {
n = 0;
scanf("%d%d", &N, &K);
for(int i = 0; i < N; i++) {
scanf("%s", str);
L[i] = n;
for(int j = 0, g = strlen(str); j < g; j++) {
Id[n] = i;
S[n++] = str[j] - 'a' + 1;
}
R[i] = n;
Id[n] = N;
S[n++] = 0;
}
}
 
void Build() {
int m = 30, *x = Height, *y = Rank;
for(int i = 0; i < m; i++) cnt[i] = 0;
for(int i = 0; i < n; i++) cnt[x[i] = S[i]]++;
for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
for(int i = 0; i < n; i++) Sa[--cnt[x[i]]] = i;
for(int k = 1, p = 0; k <= n; k <<= 1, p = 0) {
for(int i = n - k; i < n; i++) y[p++] = i;
for(int i = 0; i < n; i++)
if(Sa[i] >= k) y[p++] = Sa[i] - k;
for(int i = 0; i < m; i++) cnt[i] = 0;
for(int i = 0; i < n; i++) cnt[x[y[i]]]++;
for(int i = 1; i < m; i++) cnt[i] += cnt[i - 1];
for(int i = n; i--; ) Sa[--cnt[x[y[i]]]] = y[i];
swap(x, y);
p = 1;
x[Sa[0]] = 0;
for(int i = 1; i < n; i++) {
if(y[Sa[i]] != y[Sa[i - 1]] || y[Sa[i] + k] != y[Sa[i - 1] + k]) p++;
x[Sa[i]] = p - 1;
}
if(p >= n) break;
m = p;
}
for(int i = 0; i < n; i++) Rank[Sa[i]] = i;
Height[0] = 0;
for(int i = 0, h = 0; i < n; i++) if(Rank[i]) {
if(h) h--;
while(S[i + h] == S[Sa[Rank[i] - 1] + h]) h++;
Height[Rank[i]] = h;
}
}
 
void Init_RMQ() {
for(int i = 0; i < n; i++) mn[0][i] = Height[i];
for(int i = 1; b(i) <= n; i++)
for(int j = 0; j + b(i) <= n; j++)
mn[i][j] = min(mn[i - 1][j], mn[i - 1][j + b(i - 1)]);
}
 
inline int RMQ(int l, int r) {
if(r < l) return maxn;
int t = log2(r - l + 1);
return min(mn[t][l], mn[t][r - b(t) + 1]);
}
 
bool chk(int x, int len) {
int _L, _R;
if(Height[x] >= len) {
int l = 1, r = x;
while(l <= r) {
int m = (l + r) >> 1;
if(RMQ(m, x) >= len)
_L = m - 1, r = m - 1;
else
l = m + 1;
}
} else
_L = x;
if(x + 1 < n && Height[x + 1] >= len) {
int l = x, r = n - 1;
while(l <= r) {
int m = (l + r) >> 1;
if(RMQ(x + 1, m) >= len)
_R = m, l = m + 1;
else
r = m - 1;
}
} else
_R = x;
return ~Pos[_R] && Pos[_R] >= _L;
}
 
void Work() {
Build();
for(int i = 0; i < N; i++) cnt[i] = 0;
cnt[N] = N;
for(int i = 0, p = 0, tot = 0; i < n; i++) {
if(!cnt[Id[Sa[i]]]) tot++;
cnt[Id[Sa[i]]]++;
while(tot > K || (tot == K && cnt[Id[Sa[p]]] > 1))
if(!--cnt[Id[Sa[p++]]]) tot--;
if(tot >= K) {
Pos[i] = p;
} else
Pos[i] = -1;
}
Init_RMQ();
for(int i = 0; i < N; i++) {
ll tot = 0;
for(int j = L[i], Last = 0; j < R[i]; j++) {
int ans = max(Last - 1, 0);
while(ans < R[i] - j && chk(Rank[j], ans + 1)) ans++;
Last = ans;
tot += ans;
}
printf("%I64d ", tot);
}
puts("");
}
 
int main() {
Init();
Work();
return 0;
}

----------------------------------------------------------------------------------------------

3277: 串

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 284  Solved: 108
[Submit][Status][Discuss]

Description

字符串是oi界常考的问题。现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身)。

Input

第一行两个整数n,k。
  接下来n行每行一个字符串。

Output

 
输出一行n个整数,第i个整数表示第i个字符串的答案。

Sample Input

3 1
abc
a
ab

Sample Output

6 1 3

HINT

对于100%的数据,n,k,l<=100000

Source

BZOJ 3277: 串/ BZOJ 3473: 字符串 ( 后缀数组 + RMQ + 二分 )的更多相关文章

  1. 【BZOJ 3473】 字符串 (后缀数组+RMQ+二分 | 广义SAM)

    3473: 字符串 Description 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串? Input 第一行两个整数n,k. 接下来n行每行一个字符串 ...

  2. 【uva10829-求形如UVU的串的个数】后缀数组+rmq or 直接for水过

    题意:UVU形式的串的个数,V的长度规定,U要一样,位置不同即为不同字串 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&am ...

  3. bzoj 3277: 串 & bzoj 3473: 字符串【后缀自动机||后缀数组】

    建一个广义后缀自动机(每加完一个串都返回root),在parent树上dpsum记录合法长度,打着时间戳往上跳,最后每个串在自动机上跑一变统计答案即可. 后缀数组理解起来可能方便一点,但是难写,就只说 ...

  4. BZOJ 3277 串 & BZOJ 3473 字符串 (广义后缀自动机、时间复杂度分析、启发式合并、线段树合并、主席树)

    标签那么长是因为做法太多了... 题目链接: (bzoj 3277) https://www.lydsy.com/JudgeOnline/problem.php?id=3277 (bzoj 3473) ...

  5. BZOJ.4516.[SDOI2016]生成魔咒(后缀数组 RMQ)

    题目链接 后缀自动机做法见这(超好写啊). 后缀数组是可以做的: 本质不同的字符串的个数为 \(子串个数-\sum_{ht[i]}\),即 \(\frac{n(n+1)}{2}-\sum_{ht[i] ...

  6. bzoj 3277 串 && bzoj 3473 字符串 && bzoj 2780 [Spoj]8093 Sevenk Love Oimaster——广义后缀自动机

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277 https://www.lydsy.com/JudgeOnline/problem.p ...

  7. bzoj 3473 字符串 - 后缀数组 - 树状数组

    题目传送门 传送门 题目大意 给定n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串 先用奇怪的字符把所有字符串连接起来. 建后缀树,数每个节点的子树内包含多少属 ...

  8. BZOJ 4698: Sdoi2008 Sandy的卡片 后缀数组 + RMQ + 查分

    题目描述 Sandy和Sue的热衷于收集干脆面中的卡片. 然而,Sue收集卡片是因为卡片上漂亮的人物形象,而Sandy则是为了积攒卡片兑换超炫的人物模型. 每一张卡片都由一些数字进行标记,第i张卡片的 ...

  9. BZOJ 4698: Sdoi2008 Sandy的卡片(后缀数组+差分+二分答案)

    传送门 解题思路 看到一个子串加一个数字到另一个子串,自然可以想到差分.然后要把所有串都拼起来,求出\(height\)数组后可以二分答案来做,每次二分一个答案后统计一下连续的\(height> ...

随机推荐

  1. iOS多线程编程指南(一)关于多线程编程(转)

    原文:http://www.dreamingwish.com/article/ios-multi-threaded-programming-a-multi-threaded-programming.h ...

  2. UITabBarController 笔记(二) ViewController中加UITabBarController

    新建一个简单视图iOS工程,在ViewController的viewDidLoad中代码如下 - (void)viewDidLoad { [super viewDidLoad]; // Do any ...

  3. Love Hotels and Unicode[转]

    原文地址:http://www.reigndesign.com/blog/love-hotels-and-unicode/ 讲得挺通俗的一篇文章 On Sunday 28 October I atte ...

  4. 查看MDB格式文件数据表

    当打开一个MDB格式的ACCESS文件后,如果里面默认的都是窗体视图,要查看数据表的信息,可以“创建-查询设计”查看表信息,或是在SQL视图中编写SQL语句来实现. 或按着Shift键打开文件.

  5. 整理的一些数据库不容易想到的SQL语句实例一

    1.行转列SQL语句 SELECT * FROM ( SELECT [FID] , [Weeks] , [Qty] FROM dbo.TempTable where Weeks is not null ...

  6. Timeout expired 超时时间已到. 达到了最大池大小 错误及Max Pool Size设置

    参考数据库链接串: <add key="data" value="server=192.168.1.123; Port=3306; uid=root; pwd=ro ...

  7. 在WPF中将某张表中的数据显示到datagrid

    a.在.xaml文件中拖入一个datagrid,然后添加列名,使用Binding="{Binding 数据库中的 列名称}",如下: <DataGrid AutoGenera ...

  8. Ubuntu自带的vi编辑器太难用了,换

    由于Ubuntu预安装的是tiny版本,就会导致我们在使用上的产生不便.所以我们要安装vim的full版本. 首先,先卸掉旧版的vi,输入以下命令: sudo apt-get remove vim-c ...

  9. C 运算符与表达式

    运算(操作)是对数据的加工.最基本的运算形式常常可以用一些简洁的符号来记忆,这些符号称为运算符或操作符.被运算的对象-数据称为运算量或操作数.表达式描述了对哪些数据.以什么顺序以及施加什么样的操作.运 ...

  10. poj 2771 最大独立集

    这道题又无耻的抄袭了别人的代码. 刚开始以为是最大匹配,把条件不相符的人连一起,然后求最大匹配,感觉麻烦,然后看了别人的解题报告,是把相符的人连一起,然后减去,其实就是最大独立集. 最大独立集=|G| ...