[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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值