B4373 [GXPC-S 2025] 队伍集结 / team 题解
一眼题,但是细节很多。
首先我们按照点的坐标从左往右依次标号为
设
所以我们需要枚举
但是,这样还没有做完,考虑第
综上,有:
把这个
这样本题看似做完了,实则细节比较多,你需要注意的细节:
-
在算 dp 值的时候要特判
i = 1 ,这时cost 函数的计算方法也有变化,可以考虑加上一个参数表示是否是这种情况,进行分讨。 -
在算 dp 值的时候
j 最小可以是0 ,t 可以取到j ,这里需要特别注意,如果你不慎把j 的起点设为1 从而获得 60 pts 可能是这个原因。 -
要先对
a_i 排序,否则无法计算。 -
其他神秘的细节,似乎没了。
所以最后的时间复杂度主要来源于计算 dp 数组,时间复杂度
code:
#include <bits/stdc++.h>
#define ll long long
#define db double
#define vec vector
#define pb push_back
#define pll pair<ll, ll>
#define pr pair
#define mkp make_pair
#define endl "\n"
using namespace std;
const ll mod = 998244353;
namespace fastio {char buf[1 << 21], *p1 = buf, *p2 = buf; const ll getc() {return p1 == p2 && ( p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1 ++;}const ll read() {ll x = 0, f = 1;char ch = getc();while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getc();}while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48), ch = getc();}return x * f;} const void write(ll x) {if (x < 0) { putchar('-'), x = -x; } ll sta[35], top = 0; do {sta[top++] = x % 10, x /= 10;} while (x); while (top) putchar(sta[--top] + 48); }}
#define rd fastio::read
#define wt fastio::write
#define gc fastio::getc
ll n, m, q, k, dp[205][305]; // string s;
ll opt, l, r, x, y, z, ans = 1e18;
struct node {
ll a, b;
friend bool operator < (node x, node y) {
return x.a < y.a;
}
} a[200005] ;
ll cost(ll x, ll y, bool f) {
if (x > y) swap(x, y);
ll res = 0;
for (ll i = 1; i <= n; i++) {
if (a[i].a >= x && a[i].a <= y) {
ll ps = min(a[i].a - x, y - a[i].a);
if (x == 0 && !f) ps = y - a[i].a;
res += ps * ps * a[i].b;
}
}
return res;
}
ll costt(ll x) {
ll res = 0;
for (ll i = 1; i <= n; i++) {
if (a[i].a >= x) {
res += (a[i].a - x) * (a[i].a - x) * a[i].b;
}
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
ll i, j, u, v, w, q, res = 0, now;
cin >> n >> k; ll mxa = 0;
for (i = 1; i <= n; i++) cin >> a[i].a >> a[i].b, mxa = max(mxa, a[i].a);
sort(a + 1, a + n + 1);
memset(dp, 63, sizeof(dp));
dp[0][0] = 0;
for (i = 1; i <= k; i++) {
for (j = 0; j <= mxa; j++) {
for (ll t = 0; t <= j; t++) {
if (i == 1) {
dp[i][j] = min(dp[i][j], dp[i - 1][0] + cost(0, j, 0));
} else {
dp[i][j] = min(dp[i][j], dp[i - 1][t] + cost(t, j, 1));
}
}
}
}
for (i = 0; i <= mxa; i++) {
ans = min(ans, dp[k][i] + costt(i));
}
cout << ans;
return 0;
}
/*
dp[i][j] 表示第 i 个点设在 j 位置的答案
dp[i][j] = min(dp[i - 1][t] + w(t, j))
2 1
3 3
10 2
59
*/
AC record