题目传送门
https://www.luogu.com.cn/problem/P3961
题目分析
由于小A不能移动,想挖掘一些矿石要求已经挖掘另一些,注意到这些相互依赖的矿石组内有一个特点,即与原点连线的斜率是一定的,因此,我们把斜率为 的点都放到集合
中。然后考虑答案的更新方式,最优答案考虑了所有的
个集合,假设其由前
个集合更新而来,由于挖掘矿石耗费时间,不同时间下的最优方案表现不同,所以我们要考虑在花费时间为
的情况下,考虑前
个集合所能达到的最大收益,这样一来转移方程式就呼之欲出了:
注意到由于斜率不是整数,我们需要将每一个斜率 映射到一个整数
,并分别考虑挖掘当前集合内前
个矿石
代码
#include <iostream>
#include <cmath>
using namespace std;
int f[201][40001];
int shot[201][201];
int cnt = 0;
int n, T;
int gcd(int a, int b) {
int r = 0;
if (a < b)
swap(a, b);
while (b) {
r = a % b;
a = b;
b = r;
}
return a;
}
struct node {
int val, cost;
};
node Ore[201][201];//Ore[i][j]表示在挖取基底映射为i的前j个矿石下,所需要的成本与收益
int num[201];//num[i]表示基底映射为i的矿石数量
void Update(int pos, int W, int V) {
num[pos]++;
Ore[pos][num[pos]] = Ore[pos][num[pos] - 1];
Ore[pos][num[pos]].val += V;
Ore[pos][num[pos]].cost += W;
return;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> T;
int x, y, t, v,x_b,y_b;
for (int i = 1;i <= n;i++) {
cin >> x >> y >> t >> v;
int k = gcd(x, y);
x_b = abs(x / k), y_b = abs(y / k);
if (!shot[x_b][y_b]) {
cnt++;
shot[x_b][y_b] = cnt;
}
Update(shot[x_b][y_b], t, v);
}
for (int i = 1;i <= cnt;i++) {
for (int j = 0;j <= T;j++) {
for (int q = 0;q <= num[i];q++) {
if (j < Ore[i][q].cost)
break;
f[i][j] = max(f[i][j], f[i - 1][j - Ore[i][q].cost] + Ore[i][q].val);
}
}
}
cout << f[cnt][T];
return 0;
}
5428

被折叠的 条评论
为什么被折叠?



