T712759 都因为你 (并非贪心) 赛后题解
题目传送门
思路
观察 \(\sqrt[\sum_{j\in S}{b_j}]{\prod_{j\in S} a_{j}}\) ,发现这是一个背包问题。
设计 dp[i][j] 表示考虑前 \(i\) 个物品,\(\sum_{k\in S}{b_k}=j\) 的最大的 \(\prod_{j\in S}a_{j}\) 。
转移方程大致为 dp[i][j]=max(dp[i-1][j],dp[i-1][j-b[i]]*a[i])。
答案为 \(\max\{\sqrt[i]{dp[n][i]}\}\)
目测可拿 0 分。
发现有 \(\log_2\) 这个东西,它可以大幅减小 \(a_i\),并在 dp 时可将乘法转化为加法。
做法
设计 dp[i][j] 表示考虑前 \(i\) 个物品,\(\sum_{k\in S}{b_k}=j\) 的最大的 \(\sum_{j\in S}\log_2a_{j}\) 。
转移方程大致为 dp[i][j]=max(dp[i-1][j],dp[i-1][j-b[i]]+c[i]),\(c_i\) 表示 \(\log_2a_i\)。
答案为 \(2^{\max\{\frac{dp[n][i]}{i}\}}\)。
再用滚动背包优化一下空间。
时间复杂度:\(O(n\times\sum{b})\),可以通过 \(n\le5000,a_i\le10^{18}\)。
代码
#include<bits/stdc++.h>
using namespace std;
struct node
{
double a;
int b;
}a[5005];
long double dp[8005];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
freopen("dp.in", "r", stdin);
freopen("dp.out", "w", stdout);
int n, l, r;
cin >> n >> l >> r;
for(int i = 1; i <= n; i ++)
{
cin >> a[i].a >> a[i].b;
a[i].a = log2(a[i].a);
}
memset(dp, ~0x3f, sizeof(dp));//记得初始化
dp[0] = 0;
for(int i = 1; i <= n; i ++)
{
for(int j = 8000; j >= a[i].b; j --)
{
dp[j] = max(dp[j], dp[j - a[i].b] + a[i].a);
}
}
long double ans = 0;
for(int i = l; i <= r; i ++)
{
ans = max(ans, dp[i] / (long double)i);
}
cout << fixed << setprecision(8) << pow(2, ans);
return 0;
}
hello, I'm yuzihang, if you need to copy this, please quote this url: https://www.cnblogs.com/yuzihang/p/19375306

浙公网安备 33010602011771号