模拟4题解 T1礼物
T1
题目描述
输入格式
输出格式
样例
数据范围与提示
[概率与期望][状压DP]
n<=20所以很显然的状态压缩,
定义f[s]为状态为s时的还要走的期望步数
则f[(1<<n)-1]为 0,f[0]为所求
倒着推
f[i]=Σf[j]*q[k]+(1-Σq[k])*f[i]+1;
i 当前状态,j 转移过来的状态,Σ为 枚举i中的某一个0由1转移过来,k为之一位
显然i可由 1,以q[k]的概率买到i,和以1-Σq[k]的概率恰好碰到到已有的或没有拿出来(此时转移由i过来)的状态组成;
对于 101010
可由 111010,101110,101011 这三种状态+(1-Σq[k]绿色的1的概率)不买k的状态,转移过来
那为什么正着推不行?
当正着推时,状态转移方程中1-Σq[k]无含义,故不成立;
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const double eps=1e-12; 5 double p[22]; 6 int n; 7 long long sum=0; 8 double f[1<<21]; 9 int cot(int x) 10 { 11 int ret=1; 12 while(x&1) 13 { 14 x>>=1; 15 ret++; 16 } 17 return ret; 18 } 19 20 int main() 21 { 22 scanf("%d",&n); 23 for(int i=1;i<=n;i++) 24 { 25 int x; 26 scanf("%lf%d",&p[i],&x); 27 if(p[i]<eps)continue; 28 sum+=x; 29 } 30 if(n==1) 31 { 32 printf("%lld\n",sum); 33 double ans=1/p[1]; 34 printf("%.3lf",ans); 35 } 36 else 37 { 38 int mx=1<<n; 39 f[mx-1]=0; 40 for(int i=mx-2;i>=0;i--) 41 { 42 double tot=0.0,fs=0.0; 43 int t; 44 for(int k=i;k<mx;k+=(1<<(t-1))) 45 { 46 t=cot(k); 47 fs+=f[i|(1<<(t-1))]*p[t]; 48 tot+=p[t]; 49 } 50 f[i]=(fs+1.0)/tot; 51 } 52 printf("%lld\n%.3lf",sum,f[0]); 53 } 54 }
愿你在迷茫时,记起自己的珍贵。