CF1418G Three Occurrences 做题笔记
题意是输出所有区间满足其内部每个数要么出现
因为是区间,数量很多,发现贡献是可以抵消的,直接无脑预处理前缀的桶。
然后枚举左端点,统计答案,怎么处理呢?
疯狂地向右扩展,直到区间内有数字出现了
现在的区间内出现的数字都是
现在我们发现桶内的元素值已经不重要了,重要的是对
如何维护两个桶是否相同呢?暴力还是行不通的,我们可以把它从高到低看成一个
这么大的数还是存不下啊,我们把它对一个质数取模就行了,然后再开一个桶维护前缀桶就能快速找到在给定的区间内与桶
再来看下那个的证明,假设有个合法的区间
这样会不会重复统计呢?当然不会,我们把答案分左端点统计了啊。
然后单模数哈希过不了,写了双哈希。
#include <unordered_map> #include <time.h> #include <iostream> #define int long long using namespace std; const int mod1 = 998244353, mod2 = 1000000009; int n, l, r, ans; int a[500005], s[500005], s1[500005], s2[500005]; int p1[500005], p2[500005]; unordered_map <int, int> b, w, b_; signed main () { cin >> n; p1[0] = p2[0] = 1; for (int i = 1; i <= n; i ++) { p1[i] = p1[i - 1] * 13331 % mod1; p2[i] = p2[i - 1] * 13331 % mod2; } for (int i = 1; i <= n; i ++) cin >> a[i]; for (int i = 1; i <= n; i ++) { ++ b[a[i] ]; s1[i] = s1[i - 1] + p1[a[i] ]; s2[i] = s2[i - 1] + p2[a[i] ]; if (s1[i] >= mod1) s1[i] -= mod1; if (s2[i] >= mod2) s2[i] -= mod2; if (b[a[i] ] == 3) { b[a[i] ] = 0; s1[i] -= p1[a[i] ] * 3; s2[i] -= p2[a[i] ] * 3; s1[i] = ( (s1[i] % mod1) + mod1) % mod1; s2[i] = ( (s2[i] % mod2) + mod2) % mod2; } s[i] = s2[i] * 1000000011 + s1[i]; } b.clear (); for (l = 1; l <= n; l ++) { while (1) { if (r != n && b_[a[r + 1] ] != 3) { ++ b_[a[++ r] ]; ++ b[s[r] ]; } else break; } ans += b[s[l - 1] ]; -- b_[a[l] ]; -- b[s[l] ]; } cout << ans; return 0; }
分类:
CF 做题笔记
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异