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
*/