题解:CF2115E Gellyfish and Mayflower
posted on 2025-09-06 01:36:14 | under | source
注意到 \(c\le 200\),感性地想性价比最高的一定会被选很多次。事实上,若 \(\frac {w_i}i\le \frac {w_j}j\) 则 \(w_i j\le w_j i\),也就是将 \(j\) 个价格为 \(i\) 的改成 \(i\) 个价格为 \(j\) 的更优。容易拓展到多元的情况。因此记 \(mx\) 为性价比最高的卡片的价格,那么其它卡片总共至多被买 \(mx\) 次。
考虑枚举 \(t\) 是性价比最高的卡片,不妨一开始全买这种卡片,之后买入其它卡片时再减去对应数量的卡片 \(t\)。发现这个过程中只关心当前总花费模 \(c_t\) 是多少即可,因此记状态 \(f_{t,i,j}\) 为钦定 \(t\) 性价比最高、当前在 \(i\) 上、总花费模 \(c_t\) 为 \(j\) 时的最大值,每次减去的卡片 \(t\) 数量即为 \(\frac {j+c_i}{c_t}\)。
转移利用同余最短路转圈技巧即可,询问对 \(r\le 40000\) 跑朴素背包、其它跑上述做法即可。根据先前理论其它卡片花费至多 \((c_t)^2\) 于是不会出现奇怪情况。
总结:本题需要考察性价比最高的元素的性质,此外计算答案运用了先全选再撤销的思想。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define MAX(a, b) a = max(a, b)
const int N = 2e2 + 5, M = 4e4 + 5;
int n, m, c[N], w[N], u, v, f[N][M], T, p, r, g[N][N][N][2];
vector<int> to[N];
signed main(){
cin >> n >> m;
for(int i = 1; i <= n; ++i) scanf("%lld%lld", &c[i], &w[i]);
for(int i = 1; i <= m; ++i) scanf("%lld%lld", &u, &v), to[u].push_back(v);
for(int i = 1; i <= n; ++i){
for(int j = 0; j < M; ++j){
if(j >= c[i]) MAX(f[i][j], f[i][j - c[i]] + w[i]);
for(auto k : to[i]) MAX(f[k][j], f[i][j]);
}
}
memset(g, -0x3f, sizeof g);
for(int i = 1; i <= n; ++i){
int mx = c[i];
for(int j = 0; j < mx; ++j){
g[i][1][j][0] = 0;
if(i == 1) g[i][1][j][1] = 0;
}
for(int j = 1; j <= n; ++j){
if(w[j] * c[i] <= w[i] * c[j]){
int d = __gcd(mx, c[j]);
for(int k = 0; k < d; ++k){
for(int q = k, _ = 0; _ < 2; _ += (q == k)){
int nxt = (q + c[j]) % mx;
MAX(g[i][j][nxt][0], g[i][j][q][0] + w[j] - (q + c[j]) / mx * w[i]);
MAX(g[i][j][nxt][1], g[i][j][q][1] + w[j] - (q + c[j]) / mx * w[i]);
q = nxt;
}
}
}
for(int k = 0; k < mx; ++k)
for(auto q : to[j]){
MAX(g[i][q][k][(q == i)], g[i][j][k][0]);
MAX(g[i][q][k][1], g[i][j][k][1]);
}
}
}
cin >> T;
while(T--){
scanf("%lld%lld", &p, &r);
if(r <= 40000) printf("%lld\n", f[p][r]);
else{
int ans = 0;
for(int i = 1; i <= n; ++i) MAX(ans, g[i][p][r % c[i]][1] + r / c[i] * w[i]);
printf("%lld\n", ans);
}
}
return 0;
}

浙公网安备 33010602011771号