前言

题目链接:洛谷

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

题意简述

有 \(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. 第一篇Scrum冲刺博客--原班人马打造队

    0 项目地址 点此进入 1 第一次开会/任务认领 1.1 第一次例会(2024.4.27) 第一次开会照片记录 1.2 开发认领 在查看老师在实验报告中学长的博客给了我一定的启发,我在腾讯表格中创建了 ...

  2. invalid comparison: java.util.Date and java.lang.String异常的原因

    mybatis查询时使用date类型与""比较导致的 例 <if test="params.applicationEndTime != null and param ...

  3. python重拾基础第三天

    本节内容 函数基本语法及特性 参数与局部变量 返回值 嵌套函数 递归 匿名函数 函数式编程介绍 高阶函数 内置函数 1. 函数基本语法及特性 背景提要 现在老板让你写一个监控程序,监控服务器的系统状况 ...

  4. 基于cifar数据集合成含开集、闭集噪声的数据集

    前言 噪声标签学习下的一个任务是:训练集上存在开集噪声和闭集噪声:然后在测试集上对闭集样本进行分类. 训练集中被加入的开集样本,会被均匀得打上闭集样本的标签充当开集噪声:而闭集噪声的设置与一般的噪声标 ...

  5. Python数据分析方法与技巧

    背景介绍 数据分析是数据科学领域的核心技能之一,它涉及到数据的收集.清洗.处理.分析和可视化. 数据分析是指通过收集.清洗.处理.分析和可视化数据来发现隐藏的模式.趋势和关系的过程. 数据分析是数据科 ...

  6. 微服务网关Gateway使用

    为什么需要网关? Gateway网关是我们服务的守门神,所有微服务的统一入口. 网关的核心功能特性 请求路由和负载均衡 一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转 ...

  7. Python 潮流周刊#60:Python 的包管理工具真是多啊(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  8. 咬文嚼图式的介绍二叉树、B树/B-树

    前言 因为本人天资愚钝,所以总喜欢将抽象化的事务具象化表达.对于各类眼花缭乱的树,只需要认知到它们只是一种数据结构,类似数组,切片,列表,映射等这些耳熟能详的词汇.对于一个数据结构而言,无非就是增删改 ...

  9. Go微服务开发指南

    在这篇深入探讨Go语言在微服务架构中的应用的文章中,我们介绍了选择Go构建微服务的优势.详细分析了主要的Go微服务框架,并探讨了服务发现与注册和API网关的实现及应用. 关注TechLead,复旦博士 ...

  10. vscode配置项

    因为vscode的默认配置,导致现在用的不是很舒服.总结了以下配置能让你的vscode用着更舒服. 1: 问题: 输入log按tab快速生成代码后,提示居然没了? 解决方案: "editor ...