[POI2008] POC-Trains 题解
前言
题目链接:洛谷。
时间复杂度和输入同阶的做法。
题意简述
有
题目分析
套路做法
看到字符串相等,想到使用哈希。但是要支持修改,怎么办呢?上数据结构! 当然不是,把哈希的结果看做一个数字,每次把某一位的值扣掉再加上就行了。即减去该位权值乘上原值,加上权值乘上修改后的值。
至于询问,每次操作后不可能
需要注意的是,当两个字符串是同一个的时候,可能需要小小特判。
时间复杂度
优化做法
尝试从哈希表角度分析。发现,一个字符串不断从一个相同哈希值的集合中,移动到另一个集合中,而答案就是这段时间内,该集合大小的最大值。如果考虑在删除的时候统计答案,就是在该元素加入集合后,该集合大小的最大值。
尝试把集合大小独立出来,看做单独的一个权值。我们可以把元素扩展,额外附加它在加入集合时集合的大小,发现这样删除操作就没有了,而是直接将所在集合那个附加的权值减一。这样查询,就成了一个后缀最大值。即从所在结点一直扫到哈希表末尾,取每个结点权值的最大值,得到这段时间该集合大小的最大值。
对于一条链,我们会扫过很多次,不妨从这里优化,即去除重复操作。想到,如果扫过了一个值,那下次不用再从原来的位置开始再扫一遍,而是把当前扫过来的最值记下来,下次直接从这里开始扫就行了。很类似并查集的路径压缩。
时间复杂度呢?从一个点开始,经过若干没被压缩的点,到一个已经压缩了的点,并把前者变成已经压缩了的,与总点数相关,和
代码
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; }
本文作者:XuYueming,转载请注明原文链接:https://www.cnblogs.com/XuYueming/p/18332502。
若未作特殊说明,本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】