【题目概括】
有\(n\)个点的环首尾相接,每个点都有一个权值\(val_i\)。(保证\(n|\sum val_i\))
我们可以进行的操作是将当前\(i\)个点的权值转移一部分到与其相隔\(k\)个点的点上,并且产生转移量的贡献。
题目的最终是让所有的点的权值相同,请你最小化转移的贡献。
【思路要点】
【代码】
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5 + 5;
int n, k, cnt;
ll w[N], g[N], tmp[N];
bool vis[N];
ll ave, ans = 0;
void move(int& p) {
p += k + 1;
if (p > n)
p -= n;
}
ll getAns(int p) {
cnt = 0;
while (!vis[p]) {
vis[p] = 1;
g[++cnt] = w[p];
move(p);
}
tmp[1] = 0;
for (int i = 2; i <= cnt; i++)
tmp[i] = tmp[i - 1] + g[i - 1] - ave;
sort(tmp + 1, tmp + 1 + cnt);
ll res = 0, zw = tmp[(cnt + 1) >> 1];
for (int i = 1; i <= cnt; i++)
res += abs(tmp[i] - zw);
return res;
}
int main() {
ave = 0;
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++)
scanf("%lld", &w[i]), ave += w[i];
ave /= n;
for (int i = 1; i <= n; i++)
if (!vis[i])
ans += getAns(i);
printf("%lld\n", ans);
return 0;
}