沪粤联赛 2025年3月月赛Div-2
问题 A: 道路清扫
赛时思路
贪心思路,枚举位置。(比较方法为绝对值)
赛后思路
按照排序 \(D_i\) ,枚举 \(N\) 个垃圾的起点和终点,计算移动距离即可。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
freopen("clean.in","r",stdin);
freopen("clean.out","w",stdout);
int n, m;
cin >> n >> m;
int d[m];
for (int i = 0; i < m; ++i) cin >> d[i];
sort(d, d + m);
int res = 1e9;
for (int i = 0; i <= m - n; ++i) {
int l = d[i], r = d[i + n - 1];
int dist = l >= 0 ? r : (r <= 0 ? -l : min(r - 2*l, 2*r - l));
if (dist < res) res = dist;
}
cout << res << endl;
return 0;
}
问题 B: 滑动拼图
赛前思路
正向模拟暴力骗分。
赛后思路
直接模拟会超时。
反过来考虑,计算最后左上角的格子在上一次的位置,可以做到O(n)。
代码
#include <bits/stdc++.h>
using namespace std;
struct Crystal { int x, y, c; };
int main() {
freopen("crystal.in","r",stdin);
freopen("crystal.out","w",stdout);
int Gx, Gy, N, F;
cin >> Gx >> Gy >> N >> F;
Crystal* c = new Crystal[N];
for (int i = 0; i < N; ++i)
cin >> c[i].x >> c[i].y >> c[i].c;
int** dp = new int*[Gx+1];
for (int x = 0; x <= Gx; ++x) {
dp[x] = new int[Gy+1];
for (int y = 0; y <= Gy; ++y)
dp[x][y] = (x + y) * F;
}
for (int i = 0; i < N; ++i) {
int xi = c[i].x, yi = c[i].y, ci = c[i].c;
for (int x = Gx; x >= 0; --x) {
for (int y = Gy; y >= 0; --y) {
if (x >= xi && y >= yi) {
int px = x - xi, py = y - yi;
if (px <= Gx && px >= 0 && py <= Gy && py >= 0)
if (dp[x][y] > dp[px][py] + ci)
dp[x][y] = dp[px][py] + ci;
}
}
}
}
cout << dp[Gx][Gy] << endl;
for (int x = 0; x <= Gx; ++x) delete[] dp[x];
delete[] dp;
delete[] c;
return 0;
}
问题 C: 水晶城
赛前思路
暴力枚举。
赛后思路
考虑 DP,设 $ dp_{x,y} $ 表示走到 \((x,y)\) 的最小费用,初始化时$dp_{x,y} = (x + y) \times F $。
对于每一颗移动水晶,刷新 DP 表,转移为$dp_{x-x_i,y-y_i}+c_i \rightarrow dp_{x,y} $。
要求的答案为\(dp_{G_x,G_y}\)。
代码
#include <bits/stdc++.h>
using namespace std;
struct Crystal { int x, y, c; };
int main() {
freopen("crystal.in","r",stdin);
freopen("crystal.out","w",stdout);
int Gx, Gy, N, F;
cin >> Gx >> Gy >> N >> F;
Crystal* c = new Crystal[N];
for (int i = 0; i < N; ++i)
cin >> c[i].x >> c[i].y >> c[i].c;
int** dp = new int*[Gx+1];
for (int x = 0; x <= Gx; ++x) {
dp[x] = new int[Gy+1];
for (int y = 0; y <= Gy; ++y)
dp[x][y] = (x + y) * F;
}
for (int i = 0; i < N; ++i) {
int xi = c[i].x, yi = c[i].y, ci = c[i].c;
for (int x = Gx; x >= 0; --x) {
for (int y = Gy; y >= 0; --y) {
if (x >= xi && y >= yi) {
int px = x - xi, py = y - yi;
if (px <= Gx && px >= 0 && py <= Gy && py >= 0)
if (dp[x][y] > dp[px][py] + ci)
dp[x][y] = dp[px][py] + ci;
}
}
}
}
cout << dp[Gx][Gy] << endl;
for (int x = 0; x <= Gx; ++x) delete[] dp[x];
delete[] dp;
delete[] c;
return 0;
}