CodeForces 1540D Inverse Inversions
小清新题。
首先容易发现每个合法的 唯一对应一个排列,大概就是每个时刻排列元素的相对顺序,然后插入到相应的位置。
但是这样太麻烦了。发现题目只要求求单点的 值。这应该有更简单的方法。
考虑令 表示 在前缀 的排名。那么我们时刻维护 ,然后遍历 到 ,若 那么令 。这样我们得到了一个 的做法。
一种优化方向是分块。预处理出每个块每个数经过后会变成什么。设 经过后变成 。容易发现 的值域为 ,也就是说它是一个 的分段函数。那么求出每一段的断点就可以二分求出一个数经过这个块后会增加多少。
考虑如何对一个块预处理 。相当于每次找到第一个 的位置 ,然后对 加 。容易树状数组维护,找到第一个位置可以树状数组上二分。
这样全部找到的位置就是分段函数的断点。
时间复杂度 。
code
// Problem: D. Inverse Inversions // Contest: Codeforces - Codeforces Round 728 (Div. 1) // URL: https://codeforces.com/problemset/problem/1540/D // Memory Limit: 512 MB // Time Limit: 5000 ms // // Powered by CP Editor (https://cpeditor.org) #include <bits/stdc++.h> #define pb emplace_back #define fst first #define scd second #define mkp make_pair #define mems(a, x) memset((a), (x), sizeof(a)) using namespace std; typedef long long ll; typedef double db; typedef unsigned long long ull; typedef long double ldb; typedef pair<ll, ll> pii; const int maxn = 100100; int n, m, a[maxn], blo, bel[maxn], L[maxn], R[maxn], f[330][330]; struct BIT { int c[maxn]; inline void update(int x, int d) { for (int i = x; i <= n; i += (i & (-i))) { c[i] += d; } } inline int find(int x) { int p = 0, s = 0; for (int i = 16; ~i; --i) { if (p + (1 << i) <= n && s + c[p + (1 << i)] < x) { s += c[p += (1 << i)]; } } return p + 1; } } B; inline void build(int x) { for (int i = L[x]; i <= R[x]; ++i) { int p = B.find(a[i]); B.update(p, 1); f[x][i - L[x] + 1] = p; } sort(f[x] + 1, f[x] + R[x] - L[x] + 2); for (int i = 1; i <= R[x] - L[x] + 1; ++i) { B.update(f[x][i], -1); } } void solve() { scanf("%d", &n); blo = sqrt(n); for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); B.update(i, 1); a[i] = i - a[i]; bel[i] = (i - 1) / blo + 1; if (!L[bel[i]]) { L[bel[i]] = i; } R[bel[i]] = i; } for (int i = 1; i <= bel[n]; ++i) { build(i); } scanf("%d", &m); while (m--) { int op, x, y; scanf("%d%d", &op, &x); if (op == 1) { scanf("%d", &y); a[x] = x - y; build(bel[x]); } else { int p = a[x]; for (int i = x + 1; i <= R[bel[x]]; ++i) { p += (a[i] <= p); } for (int i = bel[x] + 1; i <= bel[n]; ++i) { int t = upper_bound(f[i] + 1, f[i] + R[i] - L[i] + 2, p) - f[i] - 1; p += t; } printf("%d\n", p); } } } int main() { int T = 1; // scanf("%d", &T); while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?