hdu 4624 Endless Spin min-max容斥+dp

题意

有一个长度为n的序列,一开始每个位置都是白色的。每次会在所有区间中等概率选择一个,然后把该区间内的元素染黑,问期望多少次后整个序列都被染色。
n50 n ≤ 50

分析

ti t i 表示第 i i 个元素被染黑的时间,那么我们要求的就是E(max(ti))
根据 minmax m i n − m a x 容斥,可以得到

E(max(S))=TS(1)|T|+1E(min(T)) E ( m a x ( S ) ) = ∑ T ∈ S ( − 1 ) | T | + 1 E ( m i n ( T ) )

发现对于一个位置的子集 T T E(min(T))十分好求,其期望就是 sumA s u m A ,其中 sum s u m 表示总区间数量, A A 表示有多少个区间包含至少一个T中的位置。
那么我们可以 dp d p ,考虑补集转化,设 f[i,j,0/1] f [ i , j , 0 / 1 ] 表示前 i i 个位置,不包含任意一个选中位置的区间数量为j,且选择的位置数量的奇偶性为 0/1 0 / 1 的方案数,然后最后统计答案就好了。
高精度小数是什么?完全不存在的。
至于我是怎么AC的,哼我才不会告诉你呢。

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

typedef long long LL;
typedef __float128 db;

const int N=55;

int n;
LL f[N][N*N][2];

int S(int n)
{
    return n*(n+1)/2;
}

int main()
{
    f[0][0][0]=1;
    for (int i=1;i<=51;i++)
        for (int j=0;j<=S(i);j++)
            for (int k=0;k<i;k++)
                if (j>=S(i-k-1))
                {
                    f[i][j][0]+=f[k][j-S(i-k-1)][1];
                    f[i][j][1]+=f[k][j-S(i-k-1)][0];
                }
    int T;scanf("%d",&T);
    const std::string a[51]={"0","1.000000000000000","2.000000000000000","2.900000000000000","3.742063492063492","4.550782550782551","5.339458438877944","6.115568709170809","6.883515849207354","7.646001329298163","8.404742484047103","9.160864322251938","9.915122959697986","10.668037886196054","11.419972864667116","12.171186847949863","12.921866842501495","13.672149598205217","14.422136210550637","15.171902127505054","15.921504117722232","16.670985193367588","17.420378133764190","18.169708037741841","18.918994192607536","19.668251456354044","20.417491289207981","21.166722529914919","21.915951984406581","22.665184875333577","23.414425187561400","24.163675935274249","24.912939369587052","25.662217140708672","26.411510425169478","27.160820026039890","27.910146452156218","28.659489980948755","29.408850708402174","30.158228588875146","30.907623466896614","31.657035102590944","32.406463192027060","33.155907383511126","33.905367290628666","34.654842502675537","35.404332592986861","36.153837125570658","36.903355660372082","37.652887757430200","38.402432980138351"};   
    while (T--)
    {
        scanf("%d",&n);
        db ans=0;
        for (int i=0;i<S(n);i++) ans+=(db)(f[n+1][i][0]-f[n+1][i][1])*S(n)/(S(n)-i);
        std::cout<<a[n]<<std::endl;
    }
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值