标签:img font 图片 cst code spl gif splay 取出
这是道水题!?反正大佬说它水,那他就水着吧,我反正没觉得
我是实在没想到这道题就码了30行,不过这道题证明我现在对状压有了一丝丝敏感度,想到了要状压,并且想出了状压的状态,然而我连题都没看懂,样例也没搞出来,就随便骗了点分
这道题的状态就是用1代表这件商品被买过了,0表示没买过,由于他每次拿出哪件物品的都有可能,当然了也可能什么都没拿出来,那这个状态就有3个来源
1.这次买到了没买过的物品
2.这次买到了买过的物品
3.这次什么也没买到
其实2和3是一样的,都是由当前状态转移到当前状态,不过2和3共同的概率我们不可能直接得到,那就只能用1减去第一种情况出现的概率,我们试着列一下转移方程
f[i]=∑(f[i-j]*p[j])+(1-∑p[j])*f[i]+1
这个东西有了上面那些应该就很好理解了j代表的是取出来的那个1,当然必要时要把它变成第j件物品,也就是它是第几个一,这个应该是状压的常见套路吧,这个+1是因为不管你从那个状态来你都要多买一次,其实这个+1就看你怎么理解了,他应该是可以有不同的理解方式,我们给这个式子移一下项,他就变成了整个样子
f[i]=(∑(f[i-j]*p[j])+1) / ∑p[j]
然后愉快的转移就好了
1 #include<iostream> 2 #include<cstdio> 3 #define ll long long 4 #define maxn 22 5 using namespace std; 6 int n; 7 ll ans; 8 int c[1<<maxn]; 9 ll W[maxn]; 10 double gl[maxn],f[1<<maxn]; 11 int lowbit(int x) 12 { 13 return x&(-x); 14 } 15 int main() 16 { 17 scanf("%d",&n); 18 for(int i=0;i<n;++i) {int ls=(1<<i); c[ls]=i+1;} 19 for(int i=1;i<=n;++i) {scanf("%lf%lld",&gl[i],&W[i]); ans+=W[i];} 20 printf("%lld\n",ans); 21 for(int i=1;i<(1<<n);++i) 22 { 23 double sum=0; 24 for(int k=i;k;k-=lowbit(k)) 25 { 26 int ls1=lowbit(k); int ls2=c[ls1]; 27 f[i]+=f[i-ls1]*gl[ls2]; sum+=gl[ls2]; 28 } 29 f[i]=(f[i]+1.000)/sum; 30 } 31 printf("%0.3lf\n",f[(1<<n)-1]); 32 return 0; 33 }
标签:img font 图片 cst code spl gif splay 取出
原文地址:https://www.cnblogs.com/hzjuruo/p/11201870.html