CF2023D

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;
}
相关推荐
语戚17 小时前
力扣 1621. 大小为K的不重叠线段的数目:动态规划(Java 实现)
java·算法·leetcode·动态规划·力扣·dp
青山木17 小时前
Hot 100 --- 最长有效括号
java·数据结构·算法·leetcode·动态规划
这料鬼有毒18 小时前
二刷hot100-1143.最长公共子序列
算法·leetcode·动态规划
政企项目老覃19 小时前
边缘 AI 推理部署:安防零售场景下的模型裁剪与端侧落地实践
人工智能·程序人生·算法·性能优化·vllm
I_belong_to_jesus19 小时前
std::unique_ptr成员函数用法
c++
Tairitsu_H20 小时前
[C++] 拷贝构造还是赋值重载?类默认成员函数细节详解
开发语言·c++·类和对象
GreenTea21 小时前
发布 3 天登顶 HN:不生成一个字的模型 Jev,我把它的源码和黑料都扒了一遍
前端·后端·算法
汉克老师21 小时前
GESP2026年9月认证C++四级( 第一部分选择题(1~7题)精讲
c++·gesp·小学生·学c++编程
geats人山人海21 小时前
现代c++第二章 字符串
c++
庖丁解牛21 小时前
无穷小不是一个“神秘小数”,而是一场奔向 0 的过程
算法