博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HDU 5769 Substring 后缀数组
阅读量:5249 次
发布时间:2019-06-14

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

求字符串\(str\)中包含某个字符的互不相同的子串个数。

#include 
#include
#include
#include
#include
#define DBG(x) cerr << #x << " = " << x << endlusing namespace std;typedef long long LL;const int maxn = 100000 + 16;/******************************************************************** 后缀数组 Suffix Array** INIT:solver.call_fun(char* s);** CALL: solver.lcp(int i,int j); //后缀 i 与后缀 j 的最长公共前缀** SP_USE: solver.LCS(char *s1,char* s2); //最长公共字串******************************************************************/struct SuffixArray { int r[maxn]; int sa[maxn], rank[maxn], height[maxn]; int t[maxn], t2[maxn], c[maxn], n; int m;//模板长度 void init(char s[]) { n = strlen(s); for (int i = 0; i < n; i++) r[i] = int(s[i]); m = 128; } int cmp(int *r, int a, int b, int l) { return r[a] == r[b] && r[a + l] == r[b + l]; } /** 字符要先转化为正整数 待排序的字符串放在 r[]数组中,从 r[0]到 r[n-1], 长度为 n,且最大值小于 m。 所有的 r[i]都大于 0,r[n]无意义算法中置 0 函数结束后,结果放在 sa[]数组中(名次从 1..n), 从 sa[1]到 sa[n]。s[0]无意义 **/ void build_sa() { int i, k, p, *x = t, *y = t2; r[n++] = 0; for (i = 0; i < m; i++) c[i] = 0; for (i = 0; i < n; i++) c[x[i] = r[i]]++; for (i = 1; i < m; i++) c[i] += c[i - 1]; for (i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i; for (k = 1, p = 1; k < n; k *= 2, m = p) { for (p = 0, i = n - k; i < n; i++) y[p++] = i; for (i = 0; i < n; i++) if (sa[i] >= k) y[p++] = sa[i] - k; for (i = 0; i < m; i++) c[i] = 0; for (i = 0; i < n; i++) c[x[y[i]]]++; for (i = 1; i < m; i++) c[i] += c[i - 1]; for (i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i]; swap(x, y); p = 1; x[sa[0]] = 0; for (i = 1; i < n; i++) x[sa[i]] = cmp(y, sa[i - 1], sa[i], k) ? p - 1 : p++; } n--; } /** height[2..n]:height[i]保存的是 lcp(sa[i],sa[i-1]) rank[0..n-1]:rank[i]保存的是原串中 suffix[i]的名 次 **/ void getHeight() { int i, j, k = 0; for (i = 1; i <= n; i++) rank[sa[i]] = i; for (i = 0; i < n; i++) { if (k) k--; j = sa[rank[i] - 1]; while (r[i + k] == r[j + k]) k++; height[rank[i]] = k; } } int d[maxn][20];//元素从 1 编号到 n void RMQ_init(int A[], int n) { for (int i = 1; i <= n; i++) d[i][0] = A[i]; for (int j = 1; (1 << j) <= n; j++) for (int i = 1; i + (1 << (j - 1)) <= n; i++) d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]); } int RMQ(int L, int R) { int k = 0; L = rank[L]; R = rank[R]; if(L > R) swap(L, R); L++; while ((1 << (k + 1)) <= R - L + 1) k++; return min(d[L][k], d[R - (1 << k) + 1][k]); } void LCP_init() { RMQ_init(height, n); } int lcp(int i, int j) { if (rank[i] > rank[j]) swap(i, j); return RMQ(rank[i] + 1, rank[j]); } void call_fun(char s[]) { init(s);//初始化后缀数组 build_sa();//构造后缀数组 sa getHeight();//计算 height 与 rank LCP_init();//初始化 RMQ } int so(int n) { int ans = 0; for(int i = 1; i <= n; i++) { ans += (n - sa[i] - height[i]); } return ans; }} yoshiko;char s[maxn];int R[maxn];int main(int argc, char **argv) { int T; scanf("%d", &T); for(int cas = 1; cas <= T; ++cas) { char ch[4]; scanf("%s%s", ch, s); int n = strlen(s); for(int i = n - 1; i >= 0; --i) { if(i == n - 1) { if(s[i] == ch[0]) R[i] = i; else R[i] = n; } else { R[i] = R[i + 1]; if(s[i] == ch[0]) R[i] = i; } } yoshiko.call_fun(s); LL ans = 0; for(int i = 1; i <= n; ++i) { LL tmp = max(0, n - max(yoshiko.sa[i] + yoshiko.height[i], R[yoshiko.sa[i]])); ans += tmp; } printf("Case #%d: %lld\n", cas, ans); } return 0;}

转载于:https://www.cnblogs.com/ToRapture/p/7536899.html

你可能感兴趣的文章
mdb2csv
查看>>
C++ const限定符
查看>>
源代码的下载和编译读后感
查看>>
Kafka学习笔记
查看>>
【原创】Maven安装和配置
查看>>
Linux进程管理
查看>>
关于 自定义字体
查看>>
Octotree Chrome安装与使用方法
查看>>
用CALayer实现下载进度条控件
查看>>
Windows 环境下基于 Redis 的 Celery 任务调度模块的实现
查看>>
可编辑路由—Asp.NET MVC项目编译后,修改路由配置可动态加载
查看>>
UESTC 1330 柱爷与远古法阵【高斯消元】
查看>>
Tomcat修改用户名密码教程
查看>>
模块化概念
查看>>
基本排序
查看>>
前端非对称加密,后端Node.js解密(jsencrypt插件)(不需要密钥转码)
查看>>
list删除、集合遍历删除
查看>>
趣谈Java变量的可见性问题
查看>>
图标字体制作 -- 将SVG制作成图标字体文件,通过引入使用
查看>>
为Eclipse添加C/C++开发工具
查看>>