题意
有一个长度为n的序列,一开始每个位置都是白色的。每次会在所有区间中等概率选择一个,然后把该区间内的元素染黑,问期望多少次后整个序列都被染色。
n≤50
n
≤
50
分析
设
ti
t
i
表示第
i
i
个元素被染黑的时间,那么我们要求的就是。
根据
min−max
m
i
n
−
m
a
x
容斥,可以得到
E(max(S))=∑T∈S(−1)|T|+1E(min(T))
E
(
m
a
x
(
S
)
)
=
∑
T
∈
S
(
−
1
)
|
T
|
+
1
E
(
m
i
n
(
T
)
)
发现对于一个位置的子集 T T ,十分好求,其期望就是 sumA s u m A ,其中 sum s u m 表示总区间数量, A A 表示有多少个区间包含至少一个中的位置。
那么我们可以 dp d p ,考虑补集转化,设 f[i,j,0/1] f [ i , j , 0 / 1 ] 表示前 i i 个位置,不包含任意一个选中位置的区间数量为,且选择的位置数量的奇偶性为 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;
}