「BZOJ 2534」 L - gap字符串
「BZOJ 2534」 L - gap字符串
题目描述
有一种形如 \(uv u\) 形式的字符串,其中 \(u\) 是非空字符串,且 \(v\) 的长度正好为 \(L\), 那么称这个字符串为 \(L-Gap\) 字符串 给出一个字符串 \(S\), 以及一个正整数 \(L\), 问 \(S\) 中有多少个 \(L-Gap\) 子串.
\(1 \leq |S| \leq 5 \times 10^4, L \leq 10\)
### 解题思路 :
考虑要对特征串计数,不妨枚举 单个 \(u\) 的长度 \(|u|\),在串上设置 \(\left\lfloor \frac{|s|}{|u|}\right\rfloor\) 个关键点.
计算单个 \(u\) 覆盖某一关键点的所有串对应的 \(uvu\) 串的总数

考虑当前有关键点 \(P_1\) 其对应的另外一个 \(u\) 所在的左端点点为 \(P_2\)
考虑 \(P_1, P_2\) 能作为 \(uvu\) 串中两个\(u\)的左端点的话,当且仅当 \(Lcp(P_1, P_2) \geq |u|\)
那么问题就转化为,所有覆盖关键点 \(P_1\) 的 \(u\) 串,与其对应点的 \(Lcp \geq |u|\) 的个数是多少
考虑覆盖 \(P_1\) 的 \(u\) 串的左端点为 \(P_1'\) ,\((P_1 - |u| < P_1' < P_1 + |u|)\),其对应的另外一个\(u\) 的左端点为 \(P_2'\)
观察发现 \(P_1', P_2'\) 显然是由 \(P_1', P_2'\) 平移同一距离得到的
不妨求出后缀 \(P_1, P_2\) 的 \(Lcp\) 以及前缀 \(P_1, P_2\) 的 \(Lcs\),也就是图中红色和蓝色的线段
显然 \(P_1', P_2'\) 移动到线段之外后不可能满足 \(Lcp(P_1', P_2') \geq |u|\),所以答案就是线段上可行的 \(P_1'\) 数
也就是 \(\max(Lcp + Lcs - |u|, 0)\)
考虑这样做为什么是正确的
首先是时间复杂度,每次枚举一个 \(|u|\) ,对于 \(\left\lfloor \frac{|s|}{|u|}\right\rfloor\) 个关键点 \(O(1)\) 或 \(O(log|s|)\) 算 \(Lcs, Lcp\)
根据调和级数,复杂度是 \(O(|s|log|s|)\) 或 \(O(|s|log^2|s|)\),足以通过此题
接下来分析算法的正确性,也就是为什么不会算重和算漏
考虑对于每一个长度为 \(|u|\) 的 \(u\) 串,当且仅当只能覆盖一个关键点,所以如果其有答案,必然会被关键点算到且被算一次
注意 \(Lcp\) 和 \(Lcs\) 要对 \(|u|\) 取模,不然算到的答案就不是覆盖当且关键点的答案,会因为算法写挂了而算重
这里我用了二分 + \(hash\) 求 \(Lcs, Lcp\) ,是两个 \(log\) 的,实际上如果用 \(Sa\) 的话,复杂度就如上述一样,省去一个 \(log\)
/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define N (100005)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ull base = 233;
char s[N];
int n, m, ans;
ull pw[N], hs[N];
inline ull get(int l, int r){
if(l > r) return 0; return hs[r] - hs[l-1] * pw[r-l+1];
}
inline int getpre(int x, int y, int lim){
int l = 0, r = lim, ans = 0;
while(l <= r){
int mid = l + r >> 1;
if(get(x - mid + 1, x) == get(y - mid + 1, y))
ans = mid, l = mid + 1; else r = mid - 1;
}
return ans;
}
inline int getsuf(int x, int y, int lim){
int l = 0, r = lim, ans = 0;
while(l <= r){
int mid = l + r >> 1;
if(get(x, x + mid - 1) == get(y, y + mid - 1))
ans = mid, l = mid + 1; else r = mid - 1;
}
return ans;
}
inline void solve(int L, int R){
int len = (R - L + 1 - m) / 2, l1 = L, l2 = R - len + 1;
int llen = getpre(l1, l2, len), rlen = getsuf(l1, l2, len);
int now = (llen && rlen) ? llen + rlen - 1 : llen + rlen;
if(now >= len) ans += now - len + 1;
}
int main(){
pw[0] = 1, scanf("%d", &m);
scanf("%s", s + 1); int n = strlen(s + 1);
for(int i = 1; i < N; i++) pw[i] = pw[i-1] * base;
for(int i = 1; i <= n; i++) hs[i] = hs[i-1] * base + s[i];
for(int k = 1; k <= (n - m) / 2; k++)
for(int i = 1; i <= n; i += k) solve(i, i + 2 * k + m - 1);
cout << ans;
return 0;
}
「BZOJ 2534」 L - gap字符串的更多相关文章
- 「BZOJ 4502」串
「BZOJ 4502」串 题目描述 兔子们在玩字符串的游戏.首先,它们拿出了一个字符串集合 \(S\),然后它们定义一个字符串为"好"的,当且仅当它可以被分成非空的两段,其中每一段 ...
- 「BZOJ 2956」模积和
「BZOJ 2956」模积和 令 \(l=\min(n,m)\).这个 \(i\neq j\) 非常不优雅,所以我们考虑分开计算,即: \[\begin{aligned} &\sum_{i=1 ...
- 「BZOJ 4228」Tibbar的后花园
「BZOJ 4228」Tibbar的后花园 Please contact lydsy2012@163.com! 警告 解题思路 可以证明最终的图中所有点的度数都 \(< 3\) ,且不存在环长是 ...
- 「BZOJ 3645」小朋友与二叉树
「BZOJ 3645」小朋友与二叉树 解题思路 令 \(G(x)\) 为关于可选大小集合的生成函数,即 \[ G(x)=\sum[i\in c ] x^i \] 令 \(F(x)\) 第 \(n\) ...
- 「BZOJ 4289」 PA2012 Tax
「BZOJ 4289」 PA2012 Tax 题目描述 给出一个 \(N\) 个点 \(M\) 条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点 \(1\) 到点 \( ...
- Solution -「BZOJ 3812」主旋律
\(\mathcal{Description}\) Link. 给定含 \(n\) 个点 \(m\) 条边的简单有向图 \(G=(V,E)\),求 \(H=(V,E'\subseteq E)\ ...
- 「BZOJ 2434」「NOI 2011」阿狸的打字机「AC自动机」
题意 有一个打字机,支持三种操作: 字符串末尾加一个小写字母 字符串末尾减一个字符 输出这个字符串 经过不超过\(n\)次操作后有\(m\)组询问:\((x,y)\),表示第\(x\)次输出第字符串在 ...
- 「BZOJ 1001」狼抓兔子
题目链接 luogu bzoj \(Solution\) 这个貌似没有什么好讲的吧,直接按照这个给的图建图就好了啊,没有什么脑子,但是几点要注意的: 建双向边啊. 要这么写,中间还要写一个\(whil ...
- 「BZOJ 5188」「Usaco2018 Jan」MooTube
题目链接 luogu bzoj \(Describe\) 有一个\(n\)个节点的树,边有权值,定义两个节点之间的距离为两点之间的路径上的最小边权 给你\(Q\)个询问,问你与点\(v\)的距离大于等 ...
随机推荐
- virtual和abstract的区别和联系
壹. 相同 他们有些相似.有些场景用哪个都行! 1. 修饰父类.让子类重写 virtual和abstract都是用来修饰父类的,通过覆盖父类的定义,让子类重新定义. 2. 都用必须public 如 ...
- koa源码阅读[0]
koa源码阅读[0] Node.js也是写了两三年的时间了,刚开始学习Node的时候,hello world就是创建一个HttpServer,后来在工作中也是经历过Express.Koa1.x.Koa ...
- JSON.stringify()——JS转JSON字符串
JSON.stringify() JSON 通常用于与服务端交换数据. 在向服务器发送数据时一般是字符串. 我们可以使用 JSON.stringify() 方法将 JavaScript 对象转换为字符 ...
- UNIX环境高级编程学习笔记(十)为何 fork 函数会有两个不同的返回值【转】
转自:http://blog.csdn.net/fool_duck/article/details/46917377 以下是基于 linux 0.11 内核的说明. 在init/main.c第138行 ...
- openjudge-NOI 2.6-2988 计算字符串距离
题目链接:http://noi.openjudge.cn/ch0206/2988/ 题解: 首先,题目有误,少了一个添加操作 和求解LCS之类的思路类似 f[i][j]表示a序列中1..i的部分和b序 ...
- windows下制作debian U盘启动
制作平台:Windows 7 制作debian版本:debian 7.4 wheezy 1.下载引导镜像,包含三个文件:boot.img.gz(解压备用).initrd.gz 和 vmlinuz. h ...
- 自己实现的SVM源码
首先是DATA类 import java.awt.print.Printable; import java.io.File; import java.io.FileNotFoundException; ...
- UTF-8和GB2312互转的最简单快捷的方法
一.如果你想把utf-8转为GB2312 1.用记事本打开源码,把<meta http-equiv="Content-Type" content="text/htm ...
- HDU 5348 MZL's endless loop(DFS去奇数度点+欧拉回路)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5348 题目大意:给你一张图,有n个点,和m条无向边,让你把m条无向边变成有向边,使得每个节点的|出度- ...
- POJ 3026 Borg Maze(Prim+bfs求各点间距离)
题目链接:http://poj.org/problem?id=3026 题目大意:在一个y行 x列的迷宫中,有可行走的通路空格’ ‘,不可行走的墙’#’,还有两种英文字母A和S,现在从S出发,要求用 ...