題意:給定一個序列,每次隨機覆蓋一個區間(起點和長度均隨機),求期望覆蓋完整個序列長度。
min-max容斥,min(S)=n*(n+1)/2*sum(S),sum(S)表示至少包含S集合中一個點的區間數,可以考慮一個補集轉化,求一個都不包含的區間數,發現就是sigma兩個集合內點的區間數,那麼就能dp了,f(i,j)表示上一個集合內點在i,一個都不包含區間數爲j的貢獻(根據min-max容斥的式子要對奇偶分正負),最後統計答案複雜度n^4+q*n^3。但這題卡精度要麼用java要麼手寫高精度,所以我選擇網上拖標算的表......
代碼:
#include<bits/stdc++.h>
#define db long double
using namespace std;
const int N=55;
int n;
db f[N][N*N];
int g(int x)
{return x*(x+1)/2;}
void sol()
{
n=50;
for(int i=1,mx;i<=n;i++)
{
mx=g(i-1);
f[i][mx]=1;
for(int j=0;j<=mx;j++)
{
for(int nx=i+1;nx<=n;nx++)
{
f[nx][j+g(nx-i-1)]-=f[i][j];
}
}
}
}
int main()
{
const string ans[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"};
int T,tmp,tot;db res;
sol();
scanf("%d",&T);
while(T--)
{
res=0;
scanf("%d",&n),tot=g(n);
cout<<ans[n]<<'\n';continue;
for(int i=1,mx;i<=n;i++)
{
mx=g(i-1);
for(int j=0;j<=mx;j++)
{
tmp=tot-(j+g(n-i));
res+=f[i][j]*tot/tmp;
}
}
printf("%.15Lf\n",res);
}
}