[CodeForces891E]Lust-生成函数-概率与期望

Lust

A false witness that speaketh lies!

You are given a sequence containing n integers. There is a variable res that is equal to 0 initially. The following process repeats k times.

Choose an index from 1 to n uniformly at random. Name it x. Add to res the multiply of all ai’s such that 1 ≤ i ≤ n, but i ≠ x. Then, subtract ax by 1.

You have to find expected value of res at the end of the process. It can be proved that the expected value of res can be represented as an irreducible fraction . You have to find .

Input

The first line contains two integers n and k (1 ≤ n ≤ 5000, 1 ≤ k ≤ 109) — the number of elements and parameter k that is specified in the statement.

The second line contains n space separated integers a1, a2, …, an (0 ≤ ai ≤ 109).

Output

Output a single integer — the value .

Examples

input

2 1
5 5

output

5

input

1 10
80

output

10

input

2 2
0 0

output

500000003

input

9 4
0 11 12 9 20 7 8 18 2

output

169316356

一道神题……
太弱导致看着题解都推了好久……


思路:

首先,假如现在已经得到了某个操作序列,设ai被操作的次数为bi,那么它对期望值的贡献为:

cont=i=1naii=1n(aibi)

可以发现这是顺序无关的~

于是可以得到计算答案的式子:

ans=i=1naini=1bi==k1nkk!ni=1bi!i=1n(aibi)

其中,k!ni=1bi!是不全相异元素的选排列公式。

前半部分由于过于简单暂不考虑,于是考虑化简后半部分,即:

ni=1bi==k1nkk!ni=1bi!i=1n(aibi)

简单化简一下:

k!nkni=1bi==ki=1naibibi!

考虑写出求和符号及其后方内容的生成函数:

F(x)=i=1nj0aijj!xj

F(x)的第k项即为所求的答案。

观察求和符号,可以发现它很像ex的泰勒展开形式,于是有:

F(x)=i=1nex(aix)

稍微化简:

F(x)=enxi=1n(aix)

考虑对连乘符号后的式子进行O(n2)暴力多项式乘法求系数。(这步显然可以分治FFT)
于是设i=0ncixi=i=1n(aix),其中ci为求得的系数,那么有:

F(x)=enxi=0ncixi

enx重新泰勒展开,与刚才得到的多项式相乘,得到F(x)k次项系数的表达式:

[xk]F(x)=i=0ncinki(ki)!

回带到原式中,有:

ans=i=1naik!nki=0ncinki(ki)!

进行化简,得到最终的式子:

ans=i=1naii=0ncikini

O(n)计算这个式子即可~

总复杂度O(n2),瓶颈在于那个可以用分治FFT优化的地方~
也就是说这题可以换个模数或者干脆不换以出到更大的范围~

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll md=1e9+7;
const int N=5009;

int n,k,m;
ll a[N],b[N],c[N];

inline ll read()
{
    ll x=0;char ch=getchar();
    while(ch<'0' || '9'<ch)ch=getchar();
    while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
    return x;
}

inline ll qpow(ll a,ll b)
{
    ll ret=1;
    while(b)
    {
        if(b&1)ret=ret*a%md;
        a=a*a%md;b>>=1;
    }
    return ret;
}

inline int mult(ll *a,int n,ll *b,int m,ll *c)
{
    static ll d[N];
    memset(d,0,sizeof(d[0])*(n+m+5));
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            d[i+j]+=a[i]*b[j]%md;
    for(int i=0;i<n+m-1;i++)
        c[i]=d[i]%md;
    return n+m-1;
}

int main()
{
    n=read();k=read();
    for(int i=1;i<=n;i++)
        a[i]=read();

    c[0]=1;m=1;
    for(int i=1;i<=n;i++)
    {
        b[0]=a[i];b[1]=-1;
        m=mult(b,2,c,m,c);
    }

    ll ans=1,powk=1;
    ll invn=qpow(n,md-2),inv=1;
    for(int i=1;i<=n;i++)
        ans=ans*a[i]%md;
    for(int i=0;i<=n && i<=k;i++)
    {
        ans=(ans-c[i]*powk%md*inv%md+md)%md;
        powk=powk*(k-i)%md;inv=inv*invn%md;
    }

    printf("%I64d\n",ans);
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值