CF891E Lust

若随机选择为第 \(x\) 个数,得其对答案的贡献为:

\[\large \prod_{i\neq x}a_i=\prod_{i}a_i-(a_x-1)\prod_{i\neq x}a_i \]

设 \(b_i\) 为第 \(i\) 个数被选择的次数,考虑差分,得最终答案为:

\[\large \prod_{i}a_i-\prod_{i}(a_i-b_i) \]

由题意得 \(\sum\limits_{i}b_i=k\),最终答案的期望为:

\[\large \prod_{i}a_i-\frac{1}{n^k}\frac{k!}{\prod\limits_{i}b_i!}\prod_i (a_i-b_i)=\prod_{i}a_i-\frac{k!}{n^k}\prod_i \frac{a_i-b_i}{b_i!} \]

构造 \(EGF\),得:

\[\large \prod_{i}\sum_j\frac{a_i-j}{j!}x^j=\prod_{i}(a_i-x)e^x=e^{nx}\prod_{i}(a_i-x) \]

\(\left[x^k\right]e^{nx}\prod\limits_{i}(a_i-x)\) 即为所求,发现第二项为 \(n\) 次多项式,于是就可以 \(O(n^2)\) 计算该多项式的第 \(k\) 项了。

#include<bits/stdc++.h>
#define maxn 5010
#define p 1000000007
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
ll n,k,val=1,ans;
ll f[maxn],inv[maxn];
int main()
{
    read(n),read(k),inv[1]=f[0]=1;
    for(int i=2;i<=n;++i) inv[i]=(p-p/i)*inv[p%i]%p;
    for(int i=1,v;i<=n;++i)
    {
        read(v);
        for(int j=i;j>=1;--j) f[j]=(f[j]*v%p-f[j-1]+p)%p;
        f[0]=f[0]*v%p;
    }
    for(int i=0;i<=n;++i) ans=(ans+f[i]*val%p)%p,val=val*(k-i)%p*inv[n]%p;
    printf("%lld",(f[0]-ans+p)%p);
    return 0;
}
上一篇:利用select语句对列进行过滤检索


下一篇:零基础入门 SQL 系列之排序