Description

给定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% 的数据,1<=n,k<=10^5,所有字符串总长不超过10^5,字符串只包含小写字母。


思路

首先发现这东西是真的不好做。。。那就找找性质

先把所有子串的贡献拆分成每个后缀的前缀的贡献

然后考虑怎么算每个后缀的贡献

又因为对于后缀i,假设前j个前缀有贡献,那么对于后缀i+1,它的前j-1个前缀一定是有贡献的

是不是就想到了height数组的处理,很容易证明这个的复杂度是线性的

那么怎么考虑可不可以扩展呢?

因为我们要算这个串的出现次数

并且知道连接所有串的分隔符一定是不会被匹配的

所以我们可以直接二分出包含这个串的排名区间

那么就可以预处理出排名第i的字符串至少要到第j个排名的字符串才能包含k个不同的字符串

这个东西可以双指针做


一定要把预处理的指针数组初值设成INF


 #include<bits/stdc++.h>using namespace std;typedef pair<int, int> pi;
typedef long long ll;
const int N = 2e5 + 10;
const int LOG = 20;struct Suffix_Array {int s[N], n, m;int c[N], x[N], y[N];int height[N], sa[N], rank[N];int st[N][LOG], Log[N];ll sum[N]; void init(int len, char *c) {n = len, m = 0;for (int i = 1; i <= len; i++) {s[i] = c[i];m = max(m, s[i]);}}void radix_sort() {for (int i = 1; i <= m; i++) c[i] = 0;for (int i = 1; i <= n; i++) c[x[y[i]]]++;for (int i = 1; i <= m; i++) c[i] += c[i - 1];for (int i = n; i >= 1; i--) sa[c[x[y[i]]]--] = y[i];}void buildsa() {for (int i = 1; i <= n; i++) x[i] = s[i], y[i] = i;radix_sort();int now;for (int k = 1; k <= n; k <<= 1) {now = 0;for (int i = n - k + 1; i <= n; i++) y[++now] = i;for (int i = 1; i <= n; i++) if (sa[i] > k) y[++now] = sa[i] - k;radix_sort();y[sa[1]] = now = 1;for (int i = 2; i <= n; i++) y[sa[i]] = (x[sa[i]] == x[sa[i - 1]] && x[sa[i] + k] == x[sa[i - 1] + k]) ? now : ++now;swap(x, y);if (now == n) break;m = now;}}void buildrank() {for (int i = 1; i <= n; i++) rank[sa[i]] = i;}void buildsum() {for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + n - sa[i] + 1 - height[i];}void buildheight() {for (int i = 1; i <= n; i++) if (rank[i] != 1) {int k = max(height[rank[i - 1]] - 1, 0); for (; s[i + k] == s[sa[rank[i] - 1] + k]; k++);height[rank[i]] = k;}}void buildst() {Log[1] = 0;for (int i = 2; i < N; i++) Log[i] = Log[i >> 1] + 1;for (int i = 1; i <= n; i++) st[i][0] = height[i];for (int j = 1; j < LOG; j++) {for (int i = 1; i + (1 << (j - 1)) <= n; i++) {st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);}}}int queryst(int l, int r) {if (l == r) return n - sa[l] + 1;if (l > r) swap(l, r);++l; //***int k = Log[r - l + 1];return min(st[l][k], st[r - (1 << k) + 1][k]);}int querylcp(int la, int lb) {return queryst(rank[la], rank[lb]);}int querylcp(int la, int ra, int lb, int rb) {return min(min(ra - la + 1, rb - lb + 1), queryst(rank[la], rank[lb]));}void build(int len, char *c) {init(len, c);buildsa();buildrank();buildheight();buildsum();buildst();}
} Sa;char s[N], c[N];
int len[N], bg[N], ed[N], tot = 0;
int n, k, rpos[N], num[N], bel[N];bool check(int pos, int len) {int x = Sa.rank[pos], l, r;int l_line = x, r_line = x;l = 1, r = x - 1;while (l <= r) {int mid = (l + r) >> 1;if (Sa.queryst(x, mid) > len) l_line = mid, r = mid - 1;else l = mid + 1;} l = x + 1, r = tot;while (l <= r) {int mid = (l + r) >> 1;if (Sa.queryst(x, mid) > len) r_line = mid, l = mid + 1;else r = mid - 1;}return rpos[l_line] <= r_line;
}int main() {
#ifdef dream_makerfreopen("input.txt", "r", stdin);
#endifscanf("%d %d", &n, &k);for (int i = 1; i <= n; i++) {scanf("%s", c + 1);len[i] = strlen(c + 1);bg[i] = tot + 1;for (int j = 1; j <= len[i]; j++) {s[++tot] = c[j];bel[tot] = i;}ed[i] = tot;s[++tot] = '#';}Sa.build(tot, s);memset(rpos, 0x3f, sizeof(rpos)); //*****int l = 1, r = 0, cnt = 0;for (; r <= tot; r++) {if (!bel[Sa.sa[r]]) continue; ++num[bel[Sa.sa[r]]];if (num[bel[Sa.sa[r]]] == 1) ++cnt;if (cnt >= k) {for (; l <= r; l++) {if (!bel[Sa.sa[l]]) continue;if (cnt >= k) rpos[l] = r;else break;if (num[bel[Sa.sa[l]]] == 1) --cnt;--num[bel[Sa.sa[l]]];}} }for (int i = 1; i <= n; i++) {ll ans = 0; int cur = 0;for (int j = bg[i]; j <= ed[i]; j++) {cur = max(cur - 1, 0);while (j + cur <= ed[i] && check(j, cur)) ++cur;ans += cur;}printf("%lld ", ans);}return 0;
}

转载于:https://www.cnblogs.com/dream-maker-yk/p/10073765.html

BZOJ3473: 字符串【后缀数组+思维】相关推荐

  1. BZOJ3473:字符串(后缀数组,主席树,二分,ST表)

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

  2. 洛谷 P4094 [HEOI2016/TJOI2016]字符串 后缀数组+二分+主席树

    题目链接 后缀数组 题目分析: sa[i] – 第i小的后缀的编号 rank[i] --编号为i的后缀排第几: height[i] – 第i和第i-1的最长lcp最长公共前缀: 1.二分答案,答案肯定 ...

  3. 2020多校第1场A题【后缀数组+思维】

    1.首先我们发现每个后缀开头一定是0,而且开头都是0..[若干个1]..0这种格式,按照字典序的排序方式那么如果两个0之间的1越少字典序就越小.例如aaaaab=>011110,aaab=> ...

  4. Boring counting HDU - 3518 (后缀数组)

    Boring counting \[ Time Limit: 1000 ms \quad Memory Limit: 32768 kB \] 题意 给出一个字符串,求出其中出现两次及以上的子串个数,要 ...

  5. 后缀数组以及利用后缀数组求取最长公共字串

    后缀树组是一个字符串的所有后缀的排序数组.后缀是指从某个位置 i 开始到整个串末尾结束的一个子串.字符串 r 的从 第 i 个字符开始的后缀表示为 Suffix(i) ,也就是Suffix(i)=r[ ...

  6. 后缀数组原理以及实现

    后缀数组可以解决后缀排序,字符串查找以及最长重复子串等问题. 给定一个字符串求出其中最大的重复子串,例如s="it was the best time it was" 返回 &qu ...

  7. 寻找一个字符串的重复子串 后缀数组

    什么是后缀数组 令字符串 S=S[1]S[2]...S[n]S=S[1]S[2]...S[n]{\displaystyle S=S[1]S[2]...S[n]} , S[i,j]S[i,j]{\dis ...

  8. SPOJ - PHRASES Relevant Phrases of Annihilation —— 后缀数组 出现于所有字符串中两次且不重叠的最长公共子串...

    题目链接:https://vjudge.net/problem/SPOJ-PHRASES PHRASES - Relevant Phrases of Annihilation no tags  You ...

  9. 后缀数组--处理字符串的利器

    后缀数组--处理字符串的利器 后缀数组是处理字符串的有力工具.后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多功能而时间复杂度也并不逊色,而且它比后缀树所占用的内存 ...

最新文章

  1. 阿里面试官:给我说说Netty是如何在Dubbo中应用的?
  2. 任谦:实践是大数据提升项目的灵魂丨优秀毕业生专访
  3. 中文分词算法python代码_python实现中文分词FMM算法实例
  4. import _winreg:用python操作修改windows注册表
  5. 三、【SAP-PM模块】PM模块主数据
  6. svn钩子程序上传文件中文文件导致报错的处理办法
  7. 关于“只有静态常量整型数据成员才可以在类中初始化”
  8. Oracle的Case When then end的用法
  9. window.onload与body.onload
  10. 安装Microsoft-project 2016
  11. 【计算机组成原理】IEEE 754
  12. 倚天屠龙记君临天下_战斗系统
  13. RTL-SDR 学习——什么是RTL-SDR(1)
  14. 计算机职称照图片,职称计算机xp系统知识:插入图片、艺术字、图示
  15. 针对网络脆弱性的攻击图分析方法总结
  16. Unity进阶 - 动画系统 - 给人物角色制作动画
  17. 2020-11-11,单身快乐
  18. python opencv图像处理教程 github_python图像处理工具pillow opencv等练习1 旋转
  19. 知识图谱-现代知识表示理论
  20. js怎么添加html空格,javascript-在JSX中添加空格的最佳做法

热门文章

  1. 从业务在线到互联互通,钉钉宜搭进入低代码3.0阶段新模式
  2. 扩展 GRTN:云原生趋势下的 RTC 架构演进
  3. 云栖大会100位顶级大咖演讲PPT+视频全分享!
  4. 二值化_处理连续型特征:二值化与分段
  5. 基于行为树的新手引导设计
  6. 架构:消息幂等(去重)如何解决?
  7. mysql索引_效率测试(包含测试sql脚本300万条数据),可用作教学案例。
  8. 说下readyState属性是干嘛的,都有哪几个状态
  9. SQL基础【十一、分页 limit top rownum】
  10. plsql学习范例--使用utl_file包将查询结果输出到文件中