1005考试T3

1005考试T3

​ 题目大意:

​ 对于一个大小为𝑛的数集{𝑎𝑖},设其平均值为𝑥=\(\frac{\sum a_i}{n}\),则它的方差为\(\frac{∑(𝑎𝑖−𝑥)^2}{𝑛}\)。现在有一个数集,你需要求出这个数集的每个非空子集的方差之和对\(10^9+7\)取模的结果。

\(n <= 10 ^ 6\)

奥利给,化简它就完事了

​ 用到了一点点数学知识:
\(x = \frac{\sum a_i}{n}\)

​ 首先化简它:

\(\sum(𝑎𝑖−𝑥)^2\) = \(\sum a_i ^ 2 - 2 * x * \sum a_i + n * x ^ 2\) = \(\sum a_i ^ 2 - 2 * x * \sum a_i + \frac{(\sum a_i) ^ 2}{n}\) = \(\sum a_i^2 - \frac{(\sum a_i) ^ 2}{n}\)

​ 搞上分母:

\(\frac{\sum a_i ^ 2}{n} - \frac{(\sum a_i) ^ 2}{n ^ 2}\)

​ 然后我们从小到大枚举\(n\),先看前面那一坨:

\(\displaystyle \sum_{k = 1}^{n} \frac{1}{k} * C_{n - 1}^{k - 1} * \sum_{i = 1}^{n}a_i * a_i\)

​ 解释一下:前面的\(\frac{1}{k}\)就是把分母提出来,之后考虑每一个数的贡献,相当于当前确定了一定会选\(a_i\),那么剩下的\(k - 1\)个数就可以随便选了,就是\(C_{n - 1}^{k - 1}\)。每个\(a_i\)在每个数集里面的贡献当然是\(a_i ^ 2\)

​ 后面那一坨其实一样:

\(\displaystyle \sum_{k = 1}^{n} \frac{1}{k^2} * C_{n - 1}^{k - 1} * \sum_{i = 1}^{n}a_i * a_i\)

\(\displaystyle \sum_{k = 1}^{n} \frac{1}{k ^ 2} * C_{n - 2}^{k - 2} * \sum_{i = 1}^{n} \sum_{j = 1, j \not= i}^{n} a_i * a_j\)

​ 就是考虑了\(i = j\)\(i \not= j\)两种情况就好了。

​ 令\(sum1 = \displaystyle \sum_{i = 1}^{n}a_i * a_i\),那么\(sum2 = \displaystyle \sum_{i = 1}^{n} \sum_{j = 1, j \not= i}^{n} a_i * a_j = (\sum_{i = 1}^{n} a_i ) ^ 2 - \sum_{i = 1}^{n}a_i * a_i\)。这两个可以\(O(n)\)预处理,总复杂度就是\(O(n)\)

#include <bits/stdc++.h>
    
#define int long long

using namespace std;
    
inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}
    
const int N = 2e6 + 5, mod = 1e9 + 7;
int n;
long long a[N], ans1, ans2, sum1, sum2, sum3;
int fac[N], inv[N];

void make_pre() {
    fac[0] = fac[1] = inv[0] = inv[1] = 1;
    for(int i = 2;i < N; i++) fac[i] = 1ll * fac[i - 1] * i % mod;
    for(int i = 2;i < N; i++) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
    for(int i = 2;i < N; i++) inv[i] = 1ll * inv[i - 1] * inv[i] % mod; 
}

long long ksm(long long x, int y, int mod) {
    long long res = 1;
    while(y) {
        if(y & 1) res = 1ll * res * x % mod;
        x = 1ll * x * x % mod; y >>= 1;
    }
    return res;
}

long long INV(long long k) {
    return ksm(k, mod - 2, mod);
}

long long C(int n, int m) {
    if(n < m) return 0;
    return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod; 
}

signed main() {

    n = read(); make_pre();
    for(int i = 1;i <= n; i++) a[i] = read();
    for(int i = 1;i <= n; i++) sum1 = (sum1 + 1ll * a[i] * a[i]) % mod, sum2 = (sum2 + a[i]) % mod;
    sum3 = (1ll * sum2 * sum2 % mod - sum1 + mod) % mod;
    for(int k = 1;k <= n; k++) {
        ans1 = (ans1 + 1ll * INV(k) * C(n - 1, k - 1) % mod * sum1 % mod) % mod;
        ans2 = (ans2 + 1ll * INV(1ll * k * k % mod) * C(n - 1, k - 1) % mod * sum1 % mod) % mod;
        if(k != 1) ans2 = (ans2 + 1ll * INV(1ll * k * k % mod) * C(n - 2, k - 2) % mod * sum3 % mod) % mod;
    }
    printf("%lld", (ans1 - ans2 + mod) % mod);
      

    fclose(stdin); fclose(stdout);
    return 0;
}

/*
3
3 1 2

166666670

20
47 19 98 12 13 97 64 53 52 85 56 60 94 84 98 61 9 20 97 86 

482921740
*/
posted @ 2020-10-05 19:24  C锥  阅读(104)  评论(0编辑  收藏  举报