题目传送门


题目描述

夏川的生日就要到了。作为夏川形式上的男朋友,季堂打算给夏川买一些生日礼物。
商店里一共有种礼物。夏川每得到一种礼物,就会获得相应喜悦值$W_i$(每种礼物的喜悦值不能重复获得)。
每次,店员会按照一定的概率$P_i$(或者不拿出礼物),将第i种礼物拿出来。季堂每次都会将店员拿出来的礼物买下来。没有拿出来视为什么都没有买到,也算一次购买。
众所周知,白毛切开都是黑的。所以季堂希望最后夏川的喜悦值尽可能地高。
求夏川最后最大的喜悦值是多少,并求出使夏川得到这个喜悦值,季堂的期望购买次数。


输入格式

第一行,一个整数N,表示有N种礼物。
接下来N行,每行一个实数$P_i$和正整数$W_i$,表示第i种礼物被拿出来的概率和可以获得喜悦值。


输出格式

第一行,一个整数表示可以获得的最大喜悦值。
第二行,一个实数表示获得这个喜悦值的期望购买次数,保留3位小数。


样例

样例输出:

3
0.1 2
0.2 5
0.3 7

样例输出:

14
12.167


数据范围与提示

对于10%的数据,N=1。
对于30%的数据,N≤5。
对于100%的数据,N≤20,$0<{W}_{i}≤{10}^{9}$,0<${P}_{i}$≤1且$\sum \limits_{i=1}^{n}{P}_{i}≤1$。


题意解释

又是血淋淋的没看懂题,再次印证了得语文者得OI,售货员一次只可能拿出一个礼物,且每个礼物只能买一次(捂脸……)


题解

偷偷看了看数据范围,喜悦值没有负值,于是乎,第一问就解决了,肯定是把所有礼物的喜悦值加起来。

那么来考虑10%的算法,N=1,我们只需要把这件礼物买下,且这件礼物的期望购买次数是$\frac{1}{P_i}$。

再来考虑30%的算法,那么每种商品都有买或不买两种状态,那么共有$2^N$种状态,$2^{{N}^{3}}$刚好跑过。

状态可以用状压(撞鸭)DP:设dp[S]表示当前状态为S,到买到所有礼物的期望步数。

剩下的那个$N^3$算法很容易想到高斯消元。

那么我们可以写出式子:

$dp[S]=\sum \limits_{i=1}^N P_i \times dp[S']+(1-\sum \limits_{i=1}^N P_i) \times dp[S]+1$

其中,S表示当前状态,S'为上一个状态,i表示没有买过的物品。

写出这个式子,你就跟正解不远了,把式子移个项:

$\sum \limits_{i=1}^N P_i \times dp[S]=\sum \limits_{i=1}^N P_i \times dp[S']+1\\dp[S]=\frac{\sum \limits_{i=1}^N P_i \times dp[S']+1}{\sum \limits_{i=1}^N P_i}$

这就是我们的DP式子啦,时间复杂度$O(2^N)$。

注意HDU输入格式不同,而且是special judge,记得输出时多保留一位即可(跟HDU数据刚了一下午,才发现是special judge,心态瞬间爆炸……)。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n;
double p[21];
long long w[21];//记得开long long
double dp[2000000];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf%lld",&p[i],&w[i]);
p[0]+=p[i];
w[0]+=w[i];
}
printf("%lld\n",w[0]);//第一问
for(int i=(1<<n)-2;i>=0;i--)//dp
{
double flag=0.0;//分母
for(int j=1;j<=n;j++)
{
if((1<<(j-1))&i)continue;
dp[i]+=p[j]*dp[i|1<<(j-1)];
flag+=p[j];
}
dp[i]=(dp[i]+1.0)/flag;
}
cout<<fixed<<setprecision(3)<<dp[0]<<endl;//保留小数输出第二问
return 0;
}

HDU代码:

#include<bits/stdc++.h>
using namespace std;
int n;
double p[21];
double dp[2000000];
int main()
{
while(~scanf("%lld",&n))
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
scanf("%lf",&p[i]);
for(int i=(1<<n)-2;i>=0;i--)
{
double flag=0.0;
for(int j=1;j<=n;j++)
{
if((1<<(j-1))&i)continue;
dp[i]+=p[j]*dp[i|1<<(j-1)];
flag+=p[j];
}
dp[i]=(dp[i]+1.0)/flag;
}
cout<<fixed<<setprecision(4)<<dp[0]<<endl;//注意HDU是special judge
}
return 0;
}

rp++

[HDU4336]:Card Collector(概率DP)的更多相关文章

  1. hdu4336 Card Collector(概率DP,状态压缩)

    In your childhood, do you crazy for collecting the beautiful cards in the snacks? They said that, fo ...

  2. hdu4336 Card Collector 概率dp(或容斥原理?)

    题意: 买东西集齐全套卡片赢大奖.每个包装袋里面有一张卡片或者没有. 已知每种卡片出现的概率 p[i],以及所有的卡片种类的数量 n(1<=n<=20). 问集齐卡片需要买东西的数量的期望 ...

  3. HDU-4336 Card Collector 概率DP

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4336 题意:买食品收集n个卡片,每个卡片的概率分别是pi,且Σp[i]<=1,求收集n个卡片需要 ...

  4. HDU4336 Card Collector (概率dp+状压dp)

    http://acm.hdu.edu.cn/showproblem.php?pid=4336 题意:有n种卡片,一个包里会包含至多一张卡片,第i种卡片在某个包中出现的次数为pi,问将所有种类的卡片集齐 ...

  5. $HDU$ 4336 $Card\ Collector$ 概率$dp$/$Min-Max$容斥

    正解:期望 解题报告: 传送门! 先放下题意,,,已知有总共有$n$张卡片,每次有$p_i$的概率抽到第$i$张卡,求买所有卡的期望次数 $umm$看到期望自然而然想$dp$? 再一看,哇,$n\le ...

  6. hdu4336 Card Collector 状态压缩dp

    Card Collector Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...

  7. HDU 4336 Card Collector 期望dp+状压

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4336 Card Collector Time Limit: 2000/1000 MS (Java/O ...

  8. [HDU4336]Card Collector(min-max容斥,最值反演)

    Card Collector Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  9. hdu 4336 Card Collector(期望 dp 状态压缩)

    Problem Description In your childhood, people in the famous novel Water Margin, you will win an amaz ...

随机推荐

  1. Java 使用JDBC连接查询操作数据

    import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.sql. ...

  2. [TJOI2019] 甲苯先生的线段树

    臭名昭著的巧合:CF750G 题意:在无限深度的一颗线段树中询问编号和为S的简单路径条数. 题解传送门 这道题相当于在原来基础上多了询问两点间简单路径的编号的的问题. 直觉告诉我们只需要求出两点在线段 ...

  3. centos 7下nginx搭建流媒体服务器【动态添加模块】

    1.安装nginx依赖包 yum install gcc gcc-c++ openssl-devel zlib-devel pcre pcre-devel yamdi 2.下载解压nginx_mod_ ...

  4. eclipse经常弹出Subversion Native Library Not Available解决方案

  5. oracle中的多表查询和子查询以及一些注意事项

    多表查询就是使用两张表及其以上的查询.首先需要知道几个名词,笛卡尔积,内连接,外连接,子查询. 1)笛卡尔积 所谓笛卡尔积其实就是两张表数据的条数相乘得到的最后结果,例如表1有10条数据,表2有4条数 ...

  6. 七、for循环

    for循环

  7. Thymeleaf后台传值读取

    /** * 测试用Controller *  * @author  * @date 2019-08-15 */@Controller@RequestMapping("/danyu/test& ...

  8. C++ 临时对象的生存周期

    C++ 临时对象的生存周期是一个不小的坑,参考 C++ standard 第十二章第二节,总结其规则如下: 基本原则:临时变量生存到其所在的完整表达式执行完毕之后(若作为函数参数,则以函数所在的完整表 ...

  9. centos7使用cron任务的相关命令(与centos6有区别)

    一.cron任务的自启动相关命令 1.检测cron定时服务是否自启用 systemctl is-enabled crond.service 结果展示如下: enable表示已启用自启动 disable ...

  10. 清北学堂清华大学钟皓曦神仙讲课day3摘要

    ---恢复内容开始--- 今天全是DP awsl,真的好难 先从斐波那契开始: dp:满足有一个状态边界条件(f[0]=0,f[1]=1) 边界条件:不需要计算其他状态的值而可以直接得出的状态或者最底 ...