洛谷 P4065 题解
模拟赛 T1,纪念一下第一次场切紫。(话说场上这么多人切是不是都找到原了,就我这么傻想了半天)
正难则反,很容易的将题目转化为选择若干种颜色,使这些颜色在原数组中的位置连续。
设
此结论可以感性理解,不想证了。
枚举一个右端点,(左端点也可以)发现
其实也很简单,此时就需要用到线段树了,将区间
然后就是查询,区间为二分出的
本地跑了
#include <bits/stdc++.h> #define For(i, a, b) for (int i = (a); i <= (b); i++) #define foR(i, a, b) for (int i = (a); i >= (b); i--) using namespace std; int n, x, y; int aa[19]; int lg[300005], f[19][300005]; // ST 表 int c[300005]; //颜色 int pre[300005], suf[300005]; //判断一个区间是否合法 int sum[1200005]; bool cover[1200005]; //线段树 inline int read() { char ch = getchar(); int x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getchar(); } return x; } int qmax(int x, int y) { int l = lg[y - x + 1]; return max(f[l][x], f[l][y - aa[l] + 1]); } void build(int l, int r, int k) { if (l == r) { sum[k] = 1; cover[k] = 0; return; } cover[k] = 0; int mid = l + r >> 1; build(l, mid, k << 1); build(mid + 1, r, k << 1 | 1); sum[k] = sum[k << 1] + sum[k << 1 | 1]; } void pushdown(int l, int r, int k) { if (cover[k]) { cover[k << 1] = cover[k << 1 | 1] = 1; sum[k << 1] = sum[k << 1 | 1] = 0; } } void update(int l, int r, int k) { //区间覆盖为 0 if (x <= l && y >= r) { cover[k] = 1; sum[k] = 0; return; } pushdown(l, r, k); int mid = l + r >> 1; if (x <= mid) update(l, mid, k << 1); if (y > mid) update(mid + 1, r, k << 1 | 1); sum[k] = sum[k << 1] + sum[k << 1 | 1]; } int query(int l, int r, int k) { if (x <= l && y >= r) return sum[k]; pushdown(l, r, k); int mid = l + r >> 1, res = 0; if (x <= mid) res = query(l, mid, k << 1); if (y > mid) res += query(mid + 1, r, k << 1 | 1); return res; } void init() { For(i, 0, 18) aa[i] = 1 << i; lg[1] = 0; For(i, 2, 300000) lg[i] = lg[i / 2] + 1; } void solve() { n = read(); build(1, n, 1); For(i, 1, n) pre[i] = 0; For(i, 1, n) { c[i] = read(); if (!pre[c[i]]) pre[c[i]] = i; suf[c[i]] = i; } For(i, 1, n) f[0][i] = suf[c[i]]; For(j, 1, 18) for (int i = 1; i + aa[j] - 1 <= n; i++) f[j][i] = max(f[j - 1][i], f[j - 1][i + aa[j - 1]]); long long ans = 0; For(i, 1, n) { int l = i; foR(j, 18, 0) if (l > aa[j]) { int x = l - aa[j]; if (qmax(x, i) <= i) l = x; } if (pre[c[i]] != i) { x = pre[c[i]] + 1; y = i; update(1, n, 1); } if (suf[c[i]] > i) continue; x = l; y = i; ans += query(1, n, 1); } cout << ans; } signed main() { init(); int _ = 1; _ = read(); while (_--) { solve(); cout << '\n'; } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏