可以发现,如果我们枚举每个理想亮度 (X) 然后再求在这个理想亮度情况下的答案是非常难维护的。
不妨反过来,考虑每个位置 (i, i + 1) 之间对每个理想亮度 (X) 减少次数的贡献。
不难发现需要分两种情况讨论:
-
若 (a_i < a_{i + 1}),那么此时只会对 (a_i + 2 sim a_{i + 1}) 产生贡献 (1, 2, cdots a_{i + 1} - a_i - 1)
-
若 (a_i > a_{i + 1}),那么此时只会对 (a_{i} + 2 sim m, 1 sim a_{i + 1}) 产生贡献 (1, 2, cdots m - (a_{i} - a_{i + 1} - 1))
注意到只需要最后查询一次,每次修改只需添加一段等差数列直接使用二次差分即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; ++i)
const int N = 1e5 + 5;
int n, m, ans, del, a[N], d1[N], d2[N];
int read() {
char c; int x = 0, f = 1;
c = getchar();
while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
void update(int x, int y) {
if(x < y) ++d1[x + 2], --d1[y + 1], d2[y + 1] -= y - x - 1;
else ++d1[x + 2], d1[1] += m - x, d1[2] += 1 - (m - x), --d1[y + 1], d2[y + 1] -= m + y - x - 1;
}
signed main() {
n = read(), m = read();
rep(i, 1, n) a[i] = read();
rep(i, 1, n - 1) ans += (a[i] > a[i + 1]) * m + a[i + 1] - a[i];
rep(i, 1, n - 1) update(a[i], a[i + 1]);
rep(i, 1, m) d1[i] += d1[i - 1];
rep(i, 1, m) d1[i] += d1[i - 1] + d2[i];
rep(i, 1, m) del = max(del, d1[i]);
printf("%lld", ans - del);
return 0;
}
当需要考虑在每种情况下答案分别为多少的时候,一种方式是考虑使用某种方法动态维护每次的答案;另一种方式基于答案来源的线性性,以便于可以考虑每个部分对每种情况答案的贡献。