$[MtOI2019]$时间跳跃
链接:https://www.luogu.com.cn/problem/P5615
题目描述:机关有$n$条秘密通道,第$i$条秘密通道的长度为$i$,机关会从所有选择方式种等概率随机选出一些秘密通道,如果选出来的这些秘密通道能组成一个凸多边形,那么这个方案的权值就是选出的秘密通道数量,否则权值为$0$。
那么请你求出选出来秘密通道的权值的期望。
题解:首先我们知道题目要求的是秘密通道的权值之和,这样才能算期望。
通过容斥可得:总共的$-$不合法的$=$要求的
总共的可以枚举选了多少个,拿组合数算,预处理阶乘逆元即可。
求不合法的,其实就是要求对于每一个数,和等于它的数列的大小之和,令两个$dp$数组分别表示和等于$i$的数列的大小之和,和等于i的数列的总数,背包转移即可。统计总数时可以处理$dp$的前缀和。
```
#include<iostream>
#define mod 1000000007
using namespace std;
long long fac[5001],invfac[5001],f[5001],s[5001],d[5001],t[5001],n;
long long fast_pow(long long a,long long b)
{
if (b==0)
return 1;
if (b&1)
return fast_pow(a*a%mod,b/2)*a%mod;
else
return fast_pow(a*a%mod,b/2);
}
long long C(long long a,long long b)
{
return fac[b]*invfac[b-a]%mod*invfac[a]%mod;
}
int main()
{
d[0]=1;
for (int i=1;i<=5000;++i)
for (int j=5000;j>=i;--j)
{
d[j]+=d[j-i];
s[j]+=(s[j-i]+d[j-i])%mod;
d[j]%=mod;
s[j]%=mod;
}
fac[0]=1;
for (int i=1;i<=5000;++i)
fac[i]=fac[i-1]*i%mod;
invfac[5000]=fast_pow(fac[5000],mod-2);
for (int i=4999;i>=0;--i)
invfac[i]=invfac[i+1]*(i+1)%mod;
for (int i=1;i<=5000;++i)
for (int j=1;j<=i;++j)
{
f[i]+=(C(j,i)*j%mod);
f[i]%=mod;
}
d[0]=0;
for (int i=1;i<=5000;++i)
s[i]=(s[i]+s[i-1])%mod;
for (int i=1;i<=5000;++i)
d[i]=(d[i]+d[i-1])%mod;
for (int i=1;i<=5000;++i)
t[i]=((t[i-1]+s[i]+d[i]-1)%mod+mod)%mod;
int q;
cin>>q;
for (int i=1;i<=q;++i)
{
cin>>n;
cout<<((f[n]-t[n])%mod+mod)%mod*fast_pow(fast_pow(2,n),mod-2)%mod<<endl;
}
return 0;
}