link
题意:n个人围成一桌,编号0 到 n-1, 每个人有自己喜欢的菜品,每个人收到的沮丧值是喜欢的菜品距自
思路:
考虑单独一个人的沮丧值关系,如果顺指针移动桌子,那么第(p[i] - i + n) % n 次此人沮丧值为零。
即为函数的零点。函数长这样
或者
或
最多分成三段(一次函数),我们将系数独立起来,然后累加。
code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 4 * 1e5 + 10, mod = 998244353;
int n, m;
int sk[maxn], sb[maxn], p[maxn], cst[maxn];
void add(int l, int r, int k, int b) {
if (l > r) return;
sk[l] += k;
sb[l] += b;
sk[r + 1] -= k;
sb[r + 1] -= b;
}
void add(int v) {
if (v < n / 2) {
add(0, v - 1, -1, v);
add(v, v + n / 2, 1, -v);
add(v + n / 2 + 1, n - 1, -1, n + v); // n + v 尤其精妙,分奇偶进行讨论,合并后就是n + v;
} else {
add(v - n / 2, v, -1, v);
add(v + 1, n - 1, 1, -v);
add(0, v - n / 2 - 1, 1, n - v);
}
}
signed main() {
//freopen("w.ans", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(0);
//int tt; cin >> tt; while(tt--) solve();
cin >> n;
for (int i = 0; i < n; i++) {
cin >> p[i];
cst[i] = (p[i] - i + n) % n;
add(cst[i]);
}
for (int i = 1; i < n; i++) {
sb[i] += sb[i - 1];
sk[i] += sk[i - 1];
}
int ans = 1e15, sum = 0;
for (int i = 0; i < n; i++) {
ans = min(ans, sk[i] * i + sb[i]);
}
cout << ans << endl;
return 0;
/**
* Alogrithm:
* 201
* author: whc
* created: 2022年9月12日10:58:05
**/
}