CF2023D
Tags:
- DPStateShrink 动态规划状态缩减,只计算有效状态
题解:
这个题目的问题可以转化为:
选择一个子集 ,最大化他的贡献:
E=(∑iwi)∏ipi100 E=(\sum_{i}w_i) \prod_{i}\frac{pi}{100} E=(i∑wi)i∏100pi
显然当p为100时 ,一定会全选
当p不是100时:
我们令
Eodd=W∗Q E_{odd}=W*Q Eodd=W∗Q
假如我们删除游戏 qiq_iqi wiw_iwi :
Enew=(W+wi)Q∗qi E_{new}=(W+w_i){Q}*{q_i} Enew=(W+wi)Q∗qi
如果删除后更好 那么有
(W+wi)Q∗qi<W∗Qwi∗qi<W∗(1−qi) (W+w_i){Q}*{q_i}<W*Q\\ w_i*q_i<W*(1-q_i)\\ (W+wi)Q∗qi<W∗Qwi∗qi<W∗(1−qi)
根据
wi∗pi<=200000那么W∗(100−pi)>200000 w_i*p_i<=200000\\ 那么\\ W*(100-p_i)>200000 wi∗pi<=200000那么W∗(100−pi)>200000
因此最终W的上界也在200000左右
由于w是存在上界的 ,而且根据我们的直觉,因为概率是累乘的,因此最终选择的物品不会很多,不然累乘后权重会很小
对于同一个p,显然我们只会选择w最大的几个前缀元素
假设我们选择了c个概率为p的元素,那么设其中权重最小的为w_c
如果删除这个最小的元素
原来的期望为WQ 删除后为(W-w_c)Q/q;
最优的时候删除不会更好
WQ>(W−wc)Q/qwc>W(1−q)因为c个wc的总权重为cwc那么W>=cwcwc>=cwc(1−q)c<=1/(1−q)c<=100/(100−p) WQ>(W-w_c)Q/q\\ w_c>W(1-q)\\ 因为c个w_c的总权重为cw_c 那么W>=cw_c\\ w_c>=cw_c(1-q)\\ c<=1/(1-q)\\ c<=100/(100-p) WQ>(W−wc)Q/qwc>W(1−q)因为c个wc的总权重为cwc那么W>=cwcwc>=cwc(1−q)c<=1/(1−q)c<=100/(100−p)
那么也就是说,每个p最多选择100/(100-p) 个元素最为候选
那么最多的元素个数就是
∑i=199100100−i约等于482 \sum_{i=1}^{99}\frac{100}{100-i} 约等于482 i=1∑99100−i100约等于482
因此我们只需要每个概率的若干个元素候选,然后进行01背包即可
令DPi表示W为i的时候,可以获得的最大的概率乘积
code:
cpp
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2.1e5+5;
priority_queue<int>q[101];
double d[N];
void solve() {
int n;
cin>>n;
d[0]=1;
int k=0;
for(int i=0;i<n;i++){
int x,y;
cin>>x>>y;
if(x==100){
k+=y;
}else {
q[x].push(y);
}
}
for(int i=1;i<=99;i++){
for(int y=100/(100-i);y&&q[i].size();y--){
int x=q[i].top();
q[i].pop();
for(int j=N-1;j>=x;j--){
d[j]=max(d[j],d[j-x]*i/100);
}
}
}
double ans=0;
for(int i=0;i<N;i++){
ans=max(ans,(i+k)*d[i]);
}
cout<<setprecision(7)<<fixed<<ans<<'\n';
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
// cin>>t;
while(t--)solve();
return 0;
}