博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ 3415 Common Substrings
阅读量:6830 次
发布时间:2019-06-26

本文共 3912 字,大约阅读时间需要 13 分钟。

POJ_3415

    不妨设首字符在第一个字符串里的后缀为A类后缀,首字符在第二个字符串里面的后缀为B类后缀。首先要将两个字符串合并为一个字符串并用分隔符隔开,然后处理出height数组。对于任意一个A类后缀i,和任意一个B类后缀j,假设其公共前缀的长度为k,这两个后缀所能贡献出的S集合里的元素的数目就是k-K+1,当然前提是k>=K。

    但是按这样的思路,即便求k时利用height数组的性质及RMQ问题的算法,最后也只能做到O(n^2)复杂度。于是必须优化计算k的过程的时间复杂度。

    接下来先要对前面的思路做一个等价的转化,我们选择顺序遍历两次height数组,第一次遍历的时候如果遇到B类后缀,那么就计算一下这个后缀与前面的所有A类后缀对S集合里的元素数目的贡献,第二次遍历的时候如果遇到A类后缀,那么就计算一下这个后缀与前面的所有B类后缀对S集合里的元素数目的贡献。这两部分的和就是最后结果。

    接下来的问题就是怎么才能每次都快速地计算出贡献值了,也就是说我们需要维护一个变量t,表示假如遇到当前这个后缀后需要计算一次贡献,那么这个贡献值就是t,在扫描height[]的过程中也就需要不断地更新t。

    首先来说,如果将所有相邻的且值不小于K的height[]看成一组的话,那么这个组内的后缀对S的贡献只能是组内的A类与B类后缀的公共前缀产生的,于是我们只需要在一个组的范围内维护一个t即可。

    接下来的思路就交由大家思考吧,我也是在看了“维护一个单调栈”的提示后才想到的后面的思路。

#include
#include
#define MAXD 200010 char b[MAXD]; int N, M, K, sa[MAXD], rank[MAXD], height[MAXD], r[MAXD], wa[MAXD], wb[MAXD], ws[MAXD], wv[MAXD]; int s[MAXD], num[MAXD]; void init() {
int i, j, k = 0; scanf("%s", b); for(i = 0; b[i]; i ++, k ++) r[k] = b[i]; N = i; r[k ++] = '$'; scanf("%s", b); for(i = 0; b[i]; i ++, k ++) r[k] = b[i]; r[M = k] = 0; } int cmp(int *p, int x, int y, int l) {
return p[x] == p[y] && p[x + l] == p[y + l]; } void da(int n, int m) {
int i, j, p, *x = wa, *y = wb, *t; for(i = 0; i < m; i ++) ws[i] = 0; for(i = 0; i < n; i ++) ++ ws[x[i] = r[i]]; for(i = 1; i < m; i ++) ws[i] += ws[i - 1]; for(i = n - 1; i >= 0; i --) sa[-- ws[x[i]]] = i; for(j = p = 1; p < n; j *= 2, m = p) {
for(p = 0, i = n - j; i < n; i ++) y[p ++] = i; for(i = 0; i < n; i ++) if(sa[i] >= j) y[p ++] = sa[i] - j; for(i = 0; i < n; i ++) wv[i] = x[y[i]]; for(i = 0; i < m; i ++) ws[i] = 0; for(i = 0; i < n; i ++) ++ ws[wv[i]]; for(i = 1; i < m; i ++) ws[i] += ws[i - 1]; for(i = n - 1; i >= 0; i --) sa[-- ws[wv[i]]] = y[i]; for(t = x, x = y, y = t, x[sa[0]] = 0, i = p = 1; i < n; i ++) x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p ++; } } void calheight(int n) {
int i, j, k = 0; for(i = 1; i <= n; i ++) rank[sa[i]] = i; for(i = 0; i < n; height[rank[i ++]] = k) for(k ? -- k : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k ++); } void solve() {
int i, j, k, top = 0, n; long long int ans, t; da(M + 1, 128); calheight(M); ans = 0; for(i = 1; i <= M; i ++) {
if(height[i] < K) {
t = 0; top = -1; } else {
if(sa[i - 1] < N) {
n = 1; t += height[i] - K + 1; } else n = 0; while(top >= 0 && height[i] <= s[top]) {
if(num[top]) {
t -= (long long int)num[top] * (s[top] - K + 1); t += (long long int)num[top] * (height[i] - K + 1); n += num[top]; } -- top; } s[++ top] = height[i]; num[top] = n; if(sa[i] > N) ans += t; } } for(i = 1; i <= M; i ++) {
if(height[i] < K) {
t = 0; top = -1; } else {
if(sa[i - 1] > N) {
n = 1; t += height[i] - K + 1; } else n = 0; while(top >= 0 && height[i] <= s[top]) {
if(num[top]) {
t -= (long long int)num[top] * (s[top] - K + 1); t += (long long int)num[top] * (height[i] - K + 1); n += num[top]; } -- top; } s[++ top] = height[i]; num[top] = n; if(sa[i] < N) ans += t; } } printf("%lld\n", ans); } int main() {
for(;;) {
scanf("%d", &K); if(!K) break; init(); solve(); } return 0; }

转载地址:http://dwnkl.baihongyu.com/

你可能感兴趣的文章
深入剖析通信层和RPC调用的异步化(下)
查看>>
英特尔发布CPU新架构,突破性采用3D堆栈法
查看>>
CNCF接纳Harbor为沙箱项目
查看>>
三问百度云,ABC如何帮它跑赢马拉松?
查看>>
使用人工智能测试软件
查看>>
短视频时代,LinkedIn如何利用数据提高视频性能
查看>>
《Storm Applied》书评与作者访谈
查看>>
用深度学习解决冯-诺依曼结构内存性能瓶颈
查看>>
2016 “Better Software East/DevOps East/Agile Dev East”三个会议上的发言
查看>>
五大理由告诉你,再不看Kubernetes真的晚了
查看>>
编译安装php&&apahce以及pecl使用
查看>>
Amazon Aurora新增“回溯”特性,让DB集群可以回退到特定时间点
查看>>
pcl之FPFH配准
查看>>
微软投资混合连接,发布本地数据网关
查看>>
用PVS在.NET内核中发现的缺陷
查看>>
微软推出VS Code新特性,为TypeScript和JavaScript用户提供AI辅助开发功能
查看>>
开始使用MongoDB之前应该知道的14件事
查看>>
TensorFlow模型的签名推荐与快速上线\n
查看>>
【腾讯优测干货分享】从压测工具谈并发、压力、吞吐量
查看>>
推荐几款好用的书签收藏夹插件-让我们可以稍后阅读
查看>>