推公式+期望 [ 2020 Multi-University Training Road To The 3rd Building]

推公式+期望 2020 Multi-University Training Road To The 3rd Building

题目大意:

每一个点有一个权值 \(s_i\) ,定义一个计划是一对 \((i,j)\) \(1<=i<=j<=n\) ,计划的可爱程度是 \(\frac{1}{j-i+1}\sum_{k=i}^j s_k\) ,问选择一个计划的期望可爱程度是多少?

题解:

期望等于概率乘以可爱程度这个权值,又因为选每一个的期望都是一样的,所以概率是一样的,只要求出所有的权值之和即可。

答案就是:

\(s_1\) 的贡献 :\(s1+\frac{s1+s2}{2}+\frac{s1+s2+s3}{3}...\)

\(s_2\) 的贡献:\(s2+\frac{s2+s3}{2}+\frac{s2+s3+s4}{3}...\)

...

所以对于 \(\frac{1}{i}\) 它要乘的就是 \(sum[i]\)\(sum[i]\) 表示 \([1,n]\) 所有连续长度为 \(i\) 的权值之和)

所以求出这个 \(sum[i]\) ,然后再乘上 \(inv[i]\) 即是可爱程度之和,然后乘上概率即可。

#include <bits/stdc++.h>
#define debug(x) cout<<"debug:"<<#x<<" = "<<x<<endl;
using namespace std;
typedef long long ll;
const int maxn = 2e5+10;
const int mod = 1e9+7;
long long inv[maxn],pre[maxn],sum[maxn],a[maxn];
int c[maxn];
void init(int n) {
    c[0] = 1;
    for (int i = 1; i <= n; i++) c[i] = c[i - 1] * (n - i + 1) / i;
    inv[1] = 1;
    for (int i = 2; i <= n + 1; i++) {
        inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    }
}
long long finv(long long x,long long mod)
{
    long long k=mod-2,ans=1;
    while(k)
    {
        if (k&1) ans=ans*x%mod;
        x=x*x%mod;
        k>>=1;
    }
    return ans;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--) {
        ll n;
        scanf("%lld", &n);
        init(n - 1);
        for (int i = 1, x; i <= n; i++) {
            scanf("%lld", &a[i]);
            pre[i] = (pre[i - 1] + a[i]) % mod;
        }
        ll last = a[n];
        sum[1] = pre[n];
        for (int i = 2; i <= n; i++) {
            sum[i] = ((sum[i - 1] - last + pre[n] - pre[i - 1]) % mod + mod) % mod;
            last = (last + a[n - i + 1]) % mod;
        }
        ll ans = 0;
        for(int i=1;i<=n;i++) {
            ans = (ans+inv[i]*sum[i]%mod)%mod;
        }
        n = (n*(n-1)/2+n)%mod;
        ans = ans*finv(n,mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2020-08-06 19:23  EchoZQN  阅读(116)  评论(0编辑  收藏  举报