LOJ #3030. 「JOISC 2019 Day1」馕
考虑贪心。发现第 \(i\) 个人获得的愉悦度越接近 \(\frac{\sum\limits_{j=1}^L v_{i,j}}{n}\) 越好,因为给其他人的空间就越多。因此先预处理出每个人将将整个馕划分为 \(n\) 段愉悦值相同部分的端点 \(d_{i,1},d_{i,2},...,d_{i,n-1}\)。
构造第 \(j\) 段时考虑每次取最小的 \(d_{i,j}\) 作为断点并把这一段分给第 \(i\) 个人。因为上一个断点 \(\le d_{i,j-1}\)(每次取最小),所以很神奇地满足了条件。
code
// Problem: #3032. 「JOISC 2019 Day1」馕
// Contest: LibreOJ
// URL: https://loj.ac/p/3032
// Memory Limit: 268 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef __int128 lll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 2020;
ll n, m, a[maxn][maxn], b[maxn], c[maxn], f[maxn];
bool vis[maxn];
struct frac {
ll x, y;
frac(ll a = 0, ll b = 1) : x(a), y(b) {}
} d[maxn][maxn];
inline bool operator < (const frac &a, const frac &b) {
return (lll)a.x * b.y < (lll)a.y * b.x;
}
void solve() {
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
scanf("%lld", &a[i][j]);
b[i] += a[i][j];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
c[j] = n * a[i][j];
}
for (int j = 1, k = 1; j < n; ++j) {
ll t = b[i];
while (c[k] < t) {
t -= c[k];
++k;
}
c[k] -= t;
d[i][j] = frac(k * n * a[i][k] - c[k], n * a[i][k]);
}
}
for (int j = 1; j < n; ++j) {
int p = -1;
for (int i = 1; i <= n; ++i) {
if (!vis[i] && (p == -1 || d[i][j] < d[p][j])) {
p = i;
}
}
f[j] = p;
vis[p] = 1;
printf("%lld %lld\n", d[p][j].x, d[p][j].y);
}
for (int i = 1; i <= n; ++i) {
if (!vis[i]) {
f[n] = i;
break;
}
}
for (int i = 1; i <= n; ++i) {
printf("%lld ", f[i]);
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号