【题目概括】

\(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;
}
01-05 02:43