题目
分析
- 首先要注意
同一个旅游景点最多去一次
- 所以我们就可以考虑 01背包 了
- 想一下 ∑ i ∈ S b i ∑ i ∈ S a i \frac{\sum_{i\in S} b_i}{\sum_{i\in S} a_i} ∑i∈Sai∑i∈Sbi 不就是 d p [ i ] i \frac{dp[i]}{i} idp[i] ,其中 d p [ i ] dp[i] dp[i]表示使用了 i i i的能量获得的最大价值。
- 那么是不是感觉这个题特别简单啊
- 但是注意看复杂度,这样是 O ( n m ) O(nm) O(nm)的,也就是 O ( n ∗ ∑ i = 1 i ≤ n a i ) O(n*\sum_{i=1} ^{i\leq n}a_i) O(n∗∑i=1i≤nai) 的,显然这样是过不去的,但是可以拿60分。
- 那么我们这里考虑一下如何优化一下这个算法
- 现在局限我们的就是这个 m m m,那么怎么让他变小呢?
- 考虑一下这个式子的性质
- 这个式子的结果一定是在子集中单个物品的比值最大值与最小值的区间内的
- 所以对于一个已知的 d p [ i ] dp[i] dp[i] 当我们把其中比值最小的 i i i取出后,答案一定是非降的。
- 所以我们只用枚举到 110000 110000 110000即可( m + a [ i ] m+a[i] m+a[i])
- 对啦对啦,我们要放在外面枚举打擂台,因为更新的时候可能不是当前最大的,会造成操作冗余
题外话
有没有兄弟看到
∑
i
∈
S
b
i
∑
i
∈
S
a
i
\frac{\sum_{i\in S} b_i}{\sum_{i\in S} a_i}
∑i∈Sai∑i∈Sbi这个式子,立马就想分数规划的,请停止你这种罪恶的想法,他是不对的。
你二分枚举
m
i
d
mid
mid是一个近似的答案,
c
h
e
c
k
check
check 是不是能有满足限制的数量,那么你有没有想过一个问题,你选的数的比值必然是一个连续的区间(在全部里面)。
那么如果出现:
最后一个我需要它来凑够限制,但是倒数后几个代价很小,而且比值也没有答案大(相当于负优化,这个证明一下即可),那么我们就需要把倒数后几个都删掉,留下最后一个凑够限制即可。
那么这个操作应该不好做,而且这不就相当于上面的
D
P
DP
DP嘛
(
n
个
物
品
选
m
个
代
价
最
小
价
值
最
大
且
大
于
限
制
n个物品选m个代价最小价值最大且大于限制
n个物品选m个代价最小价值最大且大于限制)
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, w, m;
int dp[52300010];
int a[N], b[N];
inline int read() {
int Num = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')
f = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
Num = (Num << 1) + (Num << 3) + ch - '0';
ch = getchar();
}
return Num * f;
}
inline int gcd(int x, int y) { return !y ? x : gcd(y, x % y); }
int main() {
n = read(), w = read();
for (int i = 1; i <= n; i++) a[i] = read(), b[i] = read(), m += a[i];
if (m < w) {
puts("-1");
return 0;
}
for(int i=1;i<=m;i++) dp[i]=-1;
dp[0]=0;
double maxx = 0;
int Bit = 0;
for (int i = 1; i <= n; i++)
for (int j = 110000-a[i]; j >= 0; j--)
if(dp[j]>=0)
dp[j+a[i]] = max(dp[j+a[i]], dp[j] + b[i]);
for(int i=w;i<=110000;i++) if(dp[i]>=0)
{
double minn = (double)dp[i] / i * 1.0;
if (minn > maxx && i >= w) {
Bit = i;
maxx = minn;
}
}
printf("%d/%d", dp[Bit] / gcd(dp[Bit], Bit), Bit / gcd(dp[Bit], Bit));
return 0;
}