我们考虑用一个简单的背包处理出一个数有多少种方法被凑出,用 $i$ 个数凑 $j$ 的方案数记作 $f_{i,j}$。
那么答案是 $\frac{\sum_{i=1}^{n}\sum_{j=0}^{p}f_{i,j}i!(n-i)!}{n!}$。
但是为什么呢?
我们假设对于一个序列贝茜能够接待的奶牛数量的数量为 $X$。
那么答案是 $\sum_{i=1}^{n}E(X=i)i$,但是事实上这等价于 $\sum_{i=1}^{n}E(X \geq i)$。
我们的式子本身就是对于每一个前缀,其和 $\leq p$ 的方案数之和,$i,j$ 相当于长度和和。
这样的转化非常巧妙,值得借鉴。
假设 $n,p$ 同阶。
然后我们就可以尝试把标爆掉。
我不知道 y 总的标是什么复杂度,但是至少我们可以做到 $O(n^3)$(朴素的背包)。
考虑 f_i 本身只是一个二元多项式,问题也相当于它的一个截断的系数和。
对于每一个 $1 \leq a \leq n,1 \leq b \leq p$,求
$$f_{a,b}=[x^ay^b]\prod_{i=1}^{n}(1+xy^{A_i})$$
做一个二元多项式的 ln-exp 即可,复杂度 $O(n^2 \log n)$。
具体是几只 log 可能没想清楚,欢迎来喷。
能不能低于 $O(n^2 \log n)$ 暂且未知。
#include<bits/stdc++.h>
using namespace std;
namespace gza{
#define int long long
#define pb push_back
#define MT int TTT=R;while(TTT--)
#define pc putchar
#define R read()
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rep(i,a,b) for(int i=a;i>=b;i--)
#define m1(a,b) memset(a,b,sizeof a)
namespace IO
{
inline int read()
{
int x=0;
char ch=getchar();
bool f=0;
while(!isdigit(ch)){if(ch=='-') f=1;ch=getchar();}
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(f) x=-x;
return x;
}
template<typename T> inline void write(T x)
{
if(x<0) pc('-'),x=-x;
if(x>9) write(x/10);
pc(x%10+'0');
}
};
namespace math
{
inline int gcd(int a,int b)
{
int az=__builtin_ctz(a),bz=__builtin_ctz(b),z=(az>bz)?bz:az,t;
b>>=bz;
while(a) a>>=az,t=a-b,b=a,az=__builtin_ctz(t<0?-t:t),a=t<0?-t:t;
return b<<z;
}
inline int qmi(int a,int b,int p)
{
int res=1;
while(b)
{
if(b&1) res=res*a%p;
a=a*a%p;
b>>=1;
}
return res;
}
const int MAXN=2e6+10;
int my_fac[MAXN],my_inv[MAXN];
void init_binom(int mod)
{
my_fac[0]=1;fo(i,1,min(MAXN,mod)-1) my_fac[i]=my_fac[i-1]*i%mod;
my_inv[min(MAXN,mod)-1]=qmi(my_fac[min(MAXN,mod)-1],mod-2,mod);rep(i,min(MAXN,mod)-2,0) my_inv[i]=my_inv[i+1]*(i+1)%mod;
}
int binom(int a,int b,int mod)
{
return my_fac[a]*my_inv[b]%mod*my_inv[a-b]%mod;
}
};
using namespace IO;
using namespace math;
const int N=60;
int n,m;
int a[N];
double fac[N];
int f[N][N];
void main(){
fac[0]=1;
fo(i,1,N-1) fac[i]=fac[i-1]*i;
n=R;
fo(i,1,n) a[i]=R;
m=R;
f[0][0]=1;
fo(i,1,n) rep(j,m,a[i]) rep(k,i,1) f[k][j]+=f[k-1][j-a[i]];
double ans=0;
fo(i,1,n) fo(j,0,m) ans+=f[i][j]*fac[i]*fac[n-i];
cout<<fixed<<setprecision(6)<<ans/fac[n]<<endl;
}
}
signed main(){
gza::main();
}