前言

题目链接:洛谷

时间复杂度和输入同阶的做法。

题意简述

有 \(n\)(\(n \leq 10^3\))个长 \(m\) 的字符串,\(q\)(\(q \leq 10^5\))次操作,交换两个字符串的两个字符。问每个字符串在所有时刻,最多有几个和它相等。

题目分析

套路做法

看到字符串相等,想到使用哈希。但是要支持修改,怎么办呢?上数据结构! 当然不是,把哈希的结果看做一个数字,每次把某一位的值扣掉再加上就行了。即减去该位权值乘上原值,加上权值乘上修改后的值。

至于询问,每次操作后不可能 \(\Theta(n^2)\) 地弄。发现只会和当前修改的两个串有关,故 \(\Theta(n)\) 把这两个串的结果统计一遍。其他的串,维护一个 \(cur_i\) 表示当前 \(i\) 能和几个字符串相等。如果 \(i\) 和修改之前的串相等,就减去,如果和修改后的串相等了,再加上,最后和答案取个 \(\max\) 即可。

需要注意的是,当两个字符串是同一个的时候,可能需要小小特判。

时间复杂度 \(\Theta(nm + nq)\)。可过此题。当然,可以优化。

优化做法

尝试从哈希表角度分析。发现,一个字符串不断从一个相同哈希值的集合中,移动到另一个集合中,而答案就是这段时间内,该集合大小的最大值。如果考虑在删除的时候统计答案,就是在该元素加入集合后,该集合大小的最大值。

尝试把集合大小独立出来,看做单独的一个权值。我们可以把元素扩展,额外附加它在加入集合时集合的大小,发现这样删除操作就没有了,而是直接将所在集合那个附加的权值减一。这样查询,就成了一个后缀最大值。即从所在结点一直扫到哈希表末尾,取每个结点权值的最大值,得到这段时间该集合大小的最大值。

对于一条链,我们会扫过很多次,不妨从这里优化,即去除重复操作。想到,如果扫过了一个值,那下次不用再从原来的位置开始再扫一遍,而是把当前扫过来的最值记下来,下次直接从这里开始扫就行了。很类似并查集的路径压缩。

时间复杂度呢?每条边只会被经过一遍,和 \(n + q\) 是同阶的。总的时间复杂度是 \(\Theta(nm + q)\) 的,非常快。

代码

naive code

代码

优化

哈希值域太小会 WA,所以使用了 unordered_map,对时间复杂度没有影响。略去了快读,是最优解

#include <cstdio>
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std; const int N = 1010;
const int M = 110;
const int Q = 100010;
const int mod = 1e9 + 11;
const int bas = 1331; inline int add(int a, int b) {
return a + b >= mod ? a + b - mod : a + b;
} inline int sub(int a, int b) {
return a - b < 0 ? a - b + mod : a - b;
} inline int mul(int a, int b) {
return 1ll * a * b % mod;
} int n, m, q;
char str[N][M];
int hsh[N], res[N], pw[M];
int whr[N]; // 记录字符串对应哪一个结点 struct node {
int fa, ans;
} tree[N + Q * 2];
int tot; unordered_map<int, int> ysiz, ylst; // 哈希对应的字符串有几个、上一个哈希值为它是哪个结点 int query(int x) { // 返回后缀最大值,并路径压缩
if (tree[x].fa == x) return tree[x].ans;
int res = query(tree[x].fa);
tree[x].fa = tree[tree[x].fa].fa;
return tree[x].ans = max(tree[x].ans, res);
} void update(int x) {
int bl = hsh[x];
whr[x] = ++tot, ++ysiz[bl];
tree[tot] = {tot, ysiz[bl]};
tree[ylst[bl]].fa = tot;
ylst[bl] = tot;
} signed main() {
fread(buf, 1, MAX, stdin);
read(n), read(m), read(q);
pw[0] = 1;
for (int i = 1; i <= m; ++i)
pw[i] = mul(pw[i - 1], bas);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
hsh[i] = add(mul(hsh[i], bas), str[i][j] = readchar());
}
update(i);
}
for (int i = 1, a, x, b, y; i <= q; ++i) {
read(a), read(x), read(b), read(y);
res[a] = max(res[a], query(whr[a])), --ysiz[hsh[a]];
if (a != b) res[b] = max(res[b], query(whr[b])), --ysiz[hsh[b]];
hsh[a] = sub(hsh[a], mul(pw[m - x], str[a][x]));
hsh[b] = sub(hsh[b], mul(pw[m - y], str[b][y]));
swap(str[a][x], str[b][y]);
hsh[a] = add(hsh[a], mul(pw[m - x], str[a][x]));
hsh[b] = add(hsh[b], mul(pw[m - y], str[b][y]));
update(a);
if (a != b) update(b);
}
for (int i = 1; i <= n; ++i) {
printf("%d\n", max(res[i], query(whr[i]))); // 这里注意也要取 max
}
return 0;
}

[POI2008] POC-Trains 题解的更多相关文章

  1. 【BZOJ1125】[POI2008]Poc hash+map+SBT

    [BZOJ1125][POI2008]Poc Description n列火车,每条有l节车厢.每节车厢有一种颜色(用小写字母表示).有m次车厢交换操作.求:对于每列火车,在交换车厢的某个时刻,与其颜 ...

  2. [POI2008]枪战Maf题解

    问题 C: [POI2008]枪战Maf 时间限制: 1 Sec  内存限制: 256 MB 题目描述 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺 ...

  3. 【luogu P3469 [POI2008]BLO-Blockade】 题解

    题目链接:https://www.luogu.org/problemnew/show/P3469 #include <cstdio> #include <cstring> #i ...

  4. [POI2008] Poc (原名 Trians) Treap+Hash

    这个题和千山鸟飞绝体现出了一种用平衡树解决动态集合问题,主要套路就是蜜汁标记. 这个题我一开始用替罪羊树搞了一下对了28个点,后来我换成了Treap一搞对了14个点,再后来发现被卡了Hash我竟然在自 ...

  5. bzoj1125:[POI2008]Poc

    传送门 这个题好难卡啊. 看到这种题自然会想到字符串hash是不是,但是对于每次操作造成的影响需要\(O(n)\)的时间去更新,自然是不优的 可以发现这个更新可以用数据结构来维护,对于每个hash值开 ...

  6. Bzoj 1040 [ZJOI2008]骑士 题解

    1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5368  Solved: 2044[Submit][Status ...

  7. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  8. [POI2008]KLO && POC

    题意:给定一个序列 s1, s2,...sn,以及一个k,求一个连续的k个数,把s[i]...s[i+k-1]变成一个数s',使得sigma(|s[j]-s'|)(i<=j<=i+k-1) ...

  9. 【POI 每日题解 #4】 [POI2008]MAF-Mafia

    [POI2008]MAF-Mafia 很容易看出是拓扑 但不容易想出来怎么做[可能是我太菜 首先 入度为零的人是肯定死不了的 接着 我们分成环和链分析 对于一个链 最多的情况就是顺着一个个开枪 最后剩 ...

  10. 【BZOJ1125】【POI2008】poc - splay+哈希

    题意: Description n列火车,每条有l节车厢.每节车厢有一种颜色(用小写字母表示).有m次车厢交换操作.求:对于每列火车,在交换车厢的某个时刻,与其颜色完全相同的火车最多有多少. Inpu ...

随机推荐

  1. poj1163 the triangle 题解

    Description 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 (Figure 1) Figure 1 shows a number triangle. Write a progr ...

  2. golang如何使用指针灵活操作内存?unsafe包原理解析

    Hi 你好,我是k哥.一个大厂工作6年,还在继续搬砖的后端程序员. 我们都知道,C/C++提供了强大的万能指针void*,任何类型的指针都可以和万能指针相互转换.并且指针还可以进行加减等算数操作.那么 ...

  3. /etc/shadow文件破解,密码破解,md5,SHA256,SHA512破解

    环境 Kali系统 John the Ripper密码破解者 shadow文件解析 文件的格式为: {用户名}:{加密后的口令密码}:{口令最后修改时间距原点(1970-1-1)的天数}:{口令最小修 ...

  4. 关于Android开机动画调试的一点小小的经验

    格式要求: 开机动画图片既可以是jpg文件,也可以是png文件,只是一定要按顺序命名.文件名命名的国际惯例是五位数,即:00000.00001. 00002--也可以是文件夹名称+下划线+序数,即:p ...

  5. 一文带你深入理解SpringMVC的执行原理

    今天大致来看一下Spring MVC的执行流程是什么样的 执行流程:也就是一个请求是怎么到我们Controller的,返回值是怎么给客户端的 本文分析的问题: 文件上传的请求是怎么处理的 跨域是怎么处 ...

  6. 理解shell

    理解shell shell不单单是CLI,而是一种复杂的交互式程序. 1. shell的类型 当你登录系统时,系统启动什么样的shell程序取决于你的个人用户配置.在/etc/passwd文件中,用户 ...

  7. 如何解决jenkins插件下载过慢的问题

    1.修改/var/lib/jenkins/updates目录下的default.json文件 通过sed命令将插件的下载地址替换成国内的地址: sed -i 's#http:\/\/updates.j ...

  8. python3 安装pymssql失败 pip3 install pymssql

    python3 安装pymssql失败 报错信息: AttributeError: module 'platform' has no attribute 'linux_distribution' 解决 ...

  9. OpenWrt中的LuCi和Lua一些总结

    Lua.LuCi Lua是一种小巧的脚本语言,和Python一样,Lua脚本的运行需要Lua解释器: UCI(Unified Configuration Interface)是OpenWrt实现所有系 ...

  10. MinIO使用记录

    探索MinIO:高性能.分布式对象存储解决方案 注:本文除代码外多数为AI生成 最近因为有项目需要换成Amazon S3的云存储,所以把之前做过的minio部分做一个记录,后面也会把基于这版改造的S3 ...