经典题:均分纸牌p1031
线性传递,相邻之间可传(首尾不相邻),一次操作可传递若干张牌,求最小操作次数。
对每个a[i],先减去平均值,目标是将ai序列全部变成0,依次向右传递,推导答案易得,
g[i]为前缀和。
#include <bits/stdc++.h>
using namespace std;
int n, a[105], sum;
int main() {
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
sum += a[i];
}
sum /= n;
int ans = 0;
for (int i = 1; i <= n; i ++) {
a[i] -= sum;//减去平均数
if (a[i]) {
ans ++;
a[i + 1] += a[i];
}
}
cout << ans;
}
环形均分纸牌,p2512糖果传递。
枚举位置k,从k断开转化成问题1,重新统计前缀和,观察最后的表达式,即为货仓选址问题,找中位数即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
long long n, a[N], s[N], av, ans;
int main() {
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
av += a[i];
}
av /= n;
for (int i = 1; i <= n; i ++) {
a[i] -= av;
s[i] = s[i - 1] + a[i];
}
sort(s + 1, s + n + 1);
int k = (n + 1) / 2;
for (int i = 1; i <= n; i ++)
ans += abs(s[i] - s[k]);
cout << ans;
}
七夕祭
行和列互不影响,做两次环状均分纸牌即可。(注意开longlong)
#include <bits/stdc++.h>//环形均分纸牌 (注意开longlong)
#define int long long
using namespace std;
const int N = 1e5 + 10;
const int M = 0x3f3f3f3f;
int n, m, t, r[N], c[N];
int ans1 = M, ans2 = M;
signed main() {
cin >> n >> m >> t;
for (int i = 1; i <= t; i ++) {
int x, y;
cin >> x >> y;
r[x] ++, c[y] ++;
}
if (!(t % n)) {
ans1 = 0;
for (int i = 1; i <= n; i ++) {
r[i] -= (t / n);
r[i] += r[i - 1];//前缀和
}
sort(r + 1, r + n + 1);
int k = (n + 1) / 2;
for (int i = 1; i <= n; i ++)
ans1 += abs(r[i] - r[k]);
}
if (!(t % m)) {
ans2 = 0;
for (int i = 1; i <= m; i ++) {
c[i] -= (t / m);
c[i] += c[i - 1];
}
sort(c + 1, c + m + 1);
int k = (m + 1) / 2;
for (int i = 1; i <= m; i ++)
ans2 += abs(c[i] - c[k]);
}
if (ans1 != M && ans2 != M) printf("both %lld", ans1 + ans2);
if (ans1 != M && ans2 == M) printf("row %lld", ans1);
if (ans1 == M && ans2 != M) printf("column %lld", ans2);
if (ans1 == M && ans2 == M) printf("impossible");
return 0;
}