F智乃的算法竞赛群友(完全背包DP+贪心)
想用背包DP,但发现n规模达到1e9。
考虑对n >= upper的部分直接用性价比最高的,n < upper的范围再进行完全背包DP。upper可以人为设定,但最好不要超过1000,因为题目未限定T个测试样例的n的和,所以可能每个样例的n都超过upper,导致超时。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
const int upper = 499;
void solve() {
ll n, a, b; cin>>n>>a>>b;
vector<ll> cost = {0, 7, 8, 2};
vector<ll> val = {0, a, a+b, b};
if (n <= upper) {
vector<ll> dp(n+1, 0);
for (int i=1; i<=3; i++) {
for (ll j=cost[i]; j<=n; j++) {
dp[j] = max(dp[j], dp[j-cost[i]] + val[i]);
}
}
cout<<dp[n]<<'\n';
return ;
}
//n > upper
//1
ll res = 0;
ll fcost = -1, fval = -1;
if (8*a >= 7*(a+b) && 2*a >= 7*b) {
fcost = cost[1]; fval = val[1];
}
else if (7*(a+b) >= 8*a && 2*(a+b) >= 8*b) {
fcost = cost[2]; fval = val[2];
}
else {
fcost = cost[3]; fval = val[3];
}
ll tmp = (n-upper) / fcost;
res = tmp * fval;
n -= tmp * fcost;
vector<ll> dp(n+1, 0);
for (int i=1; i<=3; i++) {
for (ll j=cost[i]; j<=n; j++) {
dp[j] = max(dp[j], dp[j-cost[i]] + val[i]);
}
}
res += dp[n];
cout<<res<<'\n';
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T; cin>>T;
while (T--) solve();
return 0;
}

京公网安备 11010502036488号