Educational Codeforces Round 95 (Rated for Div. 2) G. Three Occurrences

首先我们随机两个数组valAx,valBx

对于数组a,记cnt表示ai 在前缀中出现的次数。

  1. cnt0mod3,则bi=valAx
  2. cnt1mod3,则bi=valBx
  3. cnt2mod3,则bi=valAxvalBx

prei表示b的前缀异或和,如果区间[l.r]内每个数的出现次数都是3的倍数,则满足prerprel1=0

再用双指针求出[l,r]表示对r来说的最大区间满足区间内任何一个数出现的次数都不超过3次。此时只要求出满足lposrprerprepos1pos的个数,即可求出r对答案产生的贡献。

#include <bits/stdc++.h> using namespace std; using i32 = int32_t; using i64 = long long; #define int i64 using vi = vector<int>; using pii = pair<int,int>; i32 main(){ ios::sync_with_stdio(false), cin.tie(nullptr); mt19937_64 rd(time(0)); int n; cin >> n; vi valA(n + 1), valB(n + 1); for(int i = 1; i <= n; i ++) valA[i] = rd(), valB[i] = rd(); vi cnt(n + 1), a(n + 1), b(n + 1), pre(n + 1); for(int i = 1; i <= n; i ++) { cin >> a[i]; cnt[a[i]] ++; if(cnt[a[i]] % 3 == 0) b[i] = valA[a[i]]; if(cnt[a[i]] % 3 == 1) b[i] = valB[a[i]]; if(cnt[a[i]] % 3 == 2) b[i] = valA[a[i]] ^ valB[a[i]]; pre[i] = pre[i - 1] ^ b[i]; } cnt = vi(n + 1); map<i64,i32> sum; sum[0] = 1; int res = 0; for(int l = 0 , r = 1; r <= n; r ++) { cnt[a[r]] ++; while(cnt[a[r]] > 3) { cnt[a[l]] --; if(l > 0) sum[pre[l - 1]] --; l ++; } res += sum[pre[r]], sum[pre[r]] ++; } cout << res << "\n"; return 0; }

__EOF__

本文作者PHarr
本文链接https://www.cnblogs.com/PHarr/p/18445826.html
关于博主:前OIer,SMUer
版权声明CC BY-NC 4.0
声援博主:如果这篇文章对您有帮助,不妨给我点个赞
posted @   PHarr  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示