「TAOI-2」Ciallo~(∠・ω< )⌒★ 题解

不难发现,答案可以分成两种:

  • 整段的

  • 中间删一点,两端凑一起的

考虑分开计算贡献。

如果 \(s\) 中存在子串等于 \(t\),那么自然,可以删左边的任何一段,或者右边的任何一段。

不妨设子串开始的位置为 \(i\),于是其贡献为 \((1 + 2 + \cdots + i - 1) + (1 + 2 + \cdots +(|s| - i - |t| + 1))\)。

接下来考虑中间删一点,两端凑一起的情况。

令 \(f_i\) 表示 \(s\) 从 \(i\) 开始与 \(t\) 的最长相同前缀的长度,\(g_i\) 表示 \(s\) 从 \(i\) 向前与 \(t\) 的最长相同后缀的长度。

NOTICE:由于需要排除第一种情况,所以对于 \(f, g\),都需要对于 \(|t| - 1\) 取 \(\min\)。

这部分可以通过哈希和二分完成(或者 Z 函数也行)

于是需要考虑 \(f, g\) 如何相互贡献。

不难发现,对于两个端点 \(i \le j\) 可以做出贡献,需要满足:

  • \(i + |t| - 1 \lt j\)。考虑中间必须删一点,所以必须严格小于,这样才不会重叠或者接在一起。

  • \(f_i + g_j \ge |t|\)。这样才能凑出完整的目标串。

那么其最终的贡献为 \(f_i + g_j - |t| + 1\)。

于是可以得到表达式:

\[\sum_{i = 1}^n \sum_{j = i + |t|}^n [f_i+ g_j \ge |t|](f_i + g_j - |t| + 1)
\]

不难发现可以倒着扫一遍,然后利用树状数组求和即可。

考场上以防万一,我用的双哈希……但好像有点多余。

#include <iostream>
#include <algorithm>
#include <string>
#include <cmath> using namespace std;
const int N = 4e5 + 7, BASE = 131, mod = 1331; string s, t; using hI = unsigned long long;
using hP = unsigned int; hI sha[N], tha[N];
hI sha2[N], tha2[N];
hI ofs[N], ofs2[N]; hI shash(int l, int r) {
hI sha1 = sha[r] - sha[l - 1] * ofs[r - l + 1];
sha1 += (sha2[r] + mod - sha2[l - 1] * ofs2[r - l + 1] % mod) % mod;
return sha1;
} hI thash(int l, int r) {
hI tha1 = tha[r] - tha[l - 1] * ofs[r - l + 1];
tha1 += (tha2[r] + mod - tha2[l - 1] * ofs2[r - l + 1] % mod) % mod;
return tha1;
} int f[N], g[N]; #define lowbit(i) (i & -i)
// 这是倒着的树状数组!
struct BIT {
long long b[N];
void update(int i, int x) {
for (; i; i -= lowbit(i)) b[i] += x;
}
long long query(int i) {
long long r = 0;
for(; i < N; i += lowbit(i)) r += b[i];
return r;
}
} cnt, sum; long long get(long long x) {
return (1 + x) * x / 2;
} int main() {
cin >> s >> t; int n = s.size(), m = t.size();
for (int i = 1; i <= n; ++i) {
sha[i] = sha[i - 1] * BASE + s[i - 1] - 2;
sha2[i] = (sha2[i - 1] * 17 % mod + s[i - 1] - 2) % mod;
} for(int i = 1; i <= m; ++i) {
tha[i] = tha[i - 1] * BASE + t[i - 1] - 2;
tha2[i] = (tha2[i - 1] * 17 % mod + t[i - 1] - 2) % mod;
} ofs[0] = ofs2[0] = 1;
for (int i = 1, ie = max(s.size(), t.size()); i <= ie; ++i) {
ofs[i] = ofs[i - 1] * BASE;
ofs2[i] = ofs2[i - 1] * 17 % mod;
} long long ans = 0; // 简单倍增
int W = 1 << ((int)log2(t.size()) + 1);
for (int i = 1; i <= n; ++i) {
f[i] = g[i] = -1; for (int w = W; w; w >>= 1) {
if (i + f[i] + w - 1 <= n && 1 + f[i] + w - 1 <= m
&& shash(i, i + f[i] + w - 1) == thash(1, 1 + f[i] + w - 1))
f[i] += w; if (i - g[i] - w + 1 > 0 && m - g[i] - w + 1 > 0
&& shash(i - g[i] - w + 1, i) == thash(m - g[i] - w + 1, m))
g[i] += w;
} if (f[i] >= m) ans += get(i - 1) + get(n - i - m + 1), --f[i];
} for (int i = n; i > m; --i) {
if (g[i] >= m) --g[i];
cnt.update(g[i], 1);
sum.update(g[i], g[i]); ans += sum.query(m - f[i - m]) + (f[i - m] - m + 1) * cnt.query(m - f[i - m]);
} cout << ans << '\n';
}

「TAOI-2」Ciallo~(∠・ω< )⌒★ 题解的更多相关文章

  1. 「GXOI / GZOI2019」简要题解

    「GXOI / GZOI2019」简要题解 LOJ#3083. 「GXOI / GZOI2019」与或和 https://loj.ac/problem/3083 题意:求一个矩阵的所有子矩阵的与和 和 ...

  2. loj#2054. 「TJOI / HEOI2016」树

    题目链接 loj#2054. 「TJOI / HEOI2016」树 题解 每次标记覆盖整棵字数,子树维护对于标记深度取max dfs序+线段树维护一下 代码 #include<cstdio> ...

  3. 【题解】#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT)

    [题解]#6622. 「THUPC 2019」找树 / findtree(Matrix Tree+FWT) 之前做这道题不理解,有一点走火入魔了,甚至想要一本近世代数来看,然后通过人类智慧思考后发现, ...

  4. 「POJ 3666」Making the Grade 题解(两种做法)

    0前言 感谢yxy童鞋的dp及暴力做法! 1 算法标签 优先队列.dp动态规划+滚动数组优化 2 题目难度 提高/提高+ CF rating:2300 3 题面 「POJ 3666」Making th ...

  5. LOJ #2542. 「PKUWC 2018」随机游走(最值反演 + 树上期望dp + FMT)

    写在这道题前面 : 网上的一些题解都不讲那个系数是怎么推得真的不良心 TAT (不是每个人都有那么厉害啊 , 我好菜啊) 而且 LOJ 过的代码千篇一律 ... 那个系数根本看不出来是什么啊 TAT ...

  6. LOJ #2802. 「CCC 2018」平衡树(整除分块 + dp)

    题面 LOJ #2802. 「CCC 2018」平衡树 题面有点难看...请认真阅读理解题意. 转化后就是,给你一个数 \(N\) ,每次选择一个 \(k \in [2, N]\) 将 \(N\) 变 ...

  7. LOJ #2541. 「PKUWC 2018」猎人杀(容斥 , 期望dp , NTT优化)

    题意 LOJ #2541. 「PKUWC 2018」猎人杀 题解 一道及其巧妙的题 , 参考了一下这位大佬的博客 ... 令 \(\displaystyle A = \sum_{i=1}^{n} w_ ...

  8. LOJ #2540. 「PKUWC 2018」随机算法(概率dp)

    题意 LOJ #2540. 「PKUWC 2018」随机算法 题解 朴素的就是 \(O(n3^n)\) dp 写了一下有 \(50pts\) ... 大概就是每个点有三个状态 , 考虑了但不在独立集中 ...

  9. LOJ #2538. 「PKUWC 2018」Slay the Spire (期望dp)

    Update on 1.5 学了 zhou888 的写法,真是又短又快. 并且空间是 \(O(n)\) 的,速度十分优秀. 题意 LOJ #2538. 「PKUWC 2018」Slay the Spi ...

  10. 「WC 2019」数树

    「WC 2019」数树 一道涨姿势的EGF好题,官方题解我并没有完全看懂,尝试用指数型生成函数和组合意义的角度推了一波.考场上只得了 44 分也暴露了我在数数的一些基本套路上的不足,后面的 \(\ex ...

随机推荐

  1. 如何迁移 Flink 任务到实时计算

    简介: 本文由阿里巴巴技术专家景丽宁(砚田)分享,主要介绍如何迁移Flink任务到实时计算 Flink 中来. 通常用户在线下主要使用 Flink run,这会造成一些问题,比如:同一个配置因版本而变 ...

  2. 代理网关设计与实现(基于NETTY)

    ​简介:本文重点在代理网关本身的设计与实现,而非代理资源的管理与维护. ​ 作者 | 新然 来源 | 阿里技术公众号 一 问题背景 平台端购置一批裸代理,来做广告异地展现审核.从外部购置的代理,使用方 ...

  3. 使用 Flink Hudi 构建流式数据湖

    ​简介: 本文介绍了 Flink Hudi 通过流计算对原有基于 mini-batch 的增量计算模型的不断优化演进. 本文介绍了 Flink Hudi 通过流计算对原有基于 mini-batch 的 ...

  4. [Contract] web3.eth.getAccounts, web3.eth.getCoinbase 使用场景区别

    web3.eth.getAccounts() 返回节点控制的账号列表(Promise returns Array) web3.eth.getCoinbase() 返回挖矿奖励所归集的地址(Promis ...

  5. VisualStudio 禁用移动文件到文件夹自动修改命名空间功能

    在 VisualStudio 2022 里的某个版本开始,将会在移动文件到其他文件夹时,自动修改命名空间,使用匹配文件夹路径的命名空间.如果这个功能能顺手将其他引用此类型的全部符号同时变更,那自然是很 ...

  6. 10.prometheus监控--监控进程process

    一.进程监控 如果想要对主机的进程进行监控,例如chronyd,sshd等服务进程以及自定义脚本程序运行状态监控.我们使用node exporter就不能实现需求了,此时就需要使用process ex ...

  7. C# - 能否让 SortedSet.RemoveWhere 内传入的委托异步执行

    TL;DR; 若想充分利用 RemoveWhere 带来的性能优势,建议传入判断是否删除元素的委托内采取同步操作.若一定要在该委托内使用异步操作,可以采用本文中绕行的方法,但摈弃了 RemoveWhe ...

  8. Educational Codeforces Round 162 (Rated for Div. 2) E

    E:Link 枚举路径两端的颜色 \(k\). 令 \(g[x]\) 表示满足以下条件的点 \(y\) 数量. $ y \in subtree[x]$ \(col[y] = k\) \(y\) 到 \ ...

  9. 一则current日志损坏的数据库恢复实例,隐藏参数的使用

    场景 之前写了一篇文章,是redo日志全部丢失的情况下,数据库实例恢复的方式.但是,这次特殊在,实例恢复失败的情况下.非常规打开数据库(数据库已经不一致了,但是可以通过expdp导出,导出重要的数据) ...

  10. LVS负载均衡(1)-- LVS概述及LVS网络模型

    目录 1. 负载均衡集群概述 2. LVS理论基础 2.1 LVS常用术语 2.2 LVS数据调度原理 2.3 LVS工作模型 2.3.1 NAT模型 2.3.2 DR模型 2.3.3 TUNNEL模 ...