51nod1687 方差求和

题目

在这里插入图片描述
题目链接

解题思路

简化公式
∑ i = 1 n ( a i − a ˉ ) 2 = ∑ i = 1 n ( a i 2 − 2 a i a ˉ + a ˉ 2 ) = ∑ i = 1 n a i 2 − 2 a ˉ ∑ i = 1 n a i + n a ˉ 2 = ∑ i = 1 n a i 2 − 2 n a ˉ 2 + n a ˉ 2 = ∑ i = 1 n a i 2 − n a ˉ 2 \sum_{i=1}^n(a_i-\bar a)^2\\=\sum_{i=1}^n(a_i^2-2a_i\bar a+\bar a^2)\\=\sum_{i=1}^na_i^2-2\bar a\sum_{i=1}^na_i+n\bar a^2\\=\sum_{i=1}^na_i^2-2n\bar a^2+n\bar a^2\\=\sum_{i=1}^na_i^2-n\bar a^2 i=1n(aiaˉ)2=i=1n(ai22aiaˉ+aˉ2)=i=1nai22aˉi=1nai+naˉ2=i=1nai22naˉ2+naˉ2=i=1nai2naˉ2
考虑增量法
n a ˉ 2 = ( ∑ i = 1 n a i ) 2 n n\bar a^2=\frac{(\sum_{i=1}^na_i)^2}{n} naˉ2=n(i=1nai)2
( x + a ) 2 n + 1 − x 2 n = n x 2 + 2 n x a + n a 2 − ( n + 1 ) x 2 n ( n + 1 ) = 2 n a x + n a 2 − x 2 n ( n + 1 ) = 2 a x + a 2 n + 1 − x 2 n ( n + 1 ) \frac{(x + a)^2}{n+1}-\frac{x^2}{n}\\=\frac{nx^2+2nxa+na^2-(n+1)x^2}{n(n+1)}\\=\frac{2nax+na^2-x^2}{n(n+1)}\\=\frac{2ax+a^2}{n+1}-\frac{x^2}{n(n+1)} n+1(x+a)2nx2=n(n+1)nx2+2nxa+na2(n+1)x2=n(n+1)2nax+na2x2=n+12ax+a2n(n+1)x2
无法摆脱与长度的关系,不可行。
考虑枚举长度,同时计算长度相同的区间
我们知道区间长度和左端点L就可以计算右端点R了。

a n s = ∑ l e n = 1 n ∑ L = 1 n − l e n + 1 ( ∑ i = L R a i 2 − l e n a ˉ 2 ) ans=\sum_{len=1}^n\sum_{L=1}^{n-len+1}(\sum_{i=L}^Ra_i^2-len\bar a^2) ans=len=1nL=1nlen+1(i=LRai2lenaˉ2)

其中 ∑ l e n = 1 n ∑ L = 1 n − l e n + 1 ∑ i = L R a i 2 = ∑ i = 1 n a i 2 ∗ i ∗ ( n − i + 1 ) \sum_{len=1}^n\sum_{L=1}^{n-len+1}\sum_{i=L}^Ra_i^2=\sum_{i=1}^na_i^2*i*(n-i+1) len=1nL=1nlen+1i=LRai2=i=1nai2i(ni+1)可以简单求出。

∑ l e n = 1 n ∑ L = 1 n − l e n + 1 l e n a ˉ 2 \sum_{len=1}^n\sum_{L=1}^{n-len+1}len\bar a^2 len=1nL=1nlen+1lenaˉ2

= ∑ l e n = 1 n 1 l e n ∑ L = 1 n − l e n + 1 ( ∑ i = L R a i ) 2 =\sum_{len=1}^n\frac{1}{len}\sum_{L=1}^{n-len+1}(\sum_{i=L}^Ra_i)^2 =len=1nlen1L=1nlen+1(i=LRai)2

= ∑ l e n = 1 n 1 l e n ∑ L = 1 n − l e n + 1 ( ∑ i = L R a i 2 + 2 ∑ i = L R ∑ j = i + 1 R a i a j ) =\sum_{len=1}^n\frac{1}{len}\sum_{L=1}^{n-len+1}(\sum_{i=L}^Ra_i^2+2\sum_{i=L}^R\sum_{j=i+1}^Ra_ia_j) =len=1nlen1L=1nlen+1(i=LRai2+2i=LRj=i+1Raiaj)

其中 ∑ l e n = 1 n 1 l e n ∑ L = 1 n − l e n + 1 ∑ i = L R a i 2 \sum_{len=1}^n\frac{1}{len}\sum_{L=1}^{n-len+1}\sum_{i=L}^Ra_i^2 len=1nlen1L=1nlen+1i=LRai2也能够简单维护。

f ( l e n ) = ∑ L = 1 n − l e n + 1 ∑ i = L R ∑ j = i + 1 R a i a j f(len)=\sum_{L=1}^{n-len+1}\sum_{i=L}^R\sum_{j=i+1}^Ra_ia_j f(len)=L=1nlen+1i=LRj=i+1Raiaj

我们发现 f ( l e n ) f(len) f(len)的二阶差分可以分为两部分,一部分可以用NTT维护,一部分可以简单维护。
整体复杂度 O ( T n l o g 2 n ) O(Tnlog_2n) O(Tnlog2n)

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

typedef long long ll;

void read(int &x) {
	x = 0; char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
}

const int N = 3e5 + 100;

namespace NTT {
#define pw(n) (1<<n)
	const int N = 262144, P = 998244353, g = 3;//或P=1004535809
	int n, m, bit, bitnum = 0, a[N + 5], b[N + 5], rev[N + 5];
	void getrev(int l) {
		for (int i = 0; i < pw(l); i++) {
			rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (l - 1));
		}
	}
	int fastpow(int a, int b) {
		int ans = 1;
		for (; b; b >>= 1, a = 1LL * a*a%P) {
			if (b & 1)ans = 1LL * ans*a%P;
		}
		return ans;
	}
	void NTT(int *s, int op) {
		for (int i = 0; i < bit; i++)if (i < rev[i])swap(s[i], s[rev[i]]);
		for (int i = 1; i < bit; i <<= 1) {
			int w = fastpow(g, (P - 1) / (i << 1));
			for (int p = i << 1, j = 0; j < bit; j += p) {
				int wk = 1;
				for (int k = j; k < i + j; k++, wk = 1LL * wk*w%P) {
					int x = s[k], y = 1LL * s[k + i] * wk%P;
					s[k] = (x + y) % P;
					s[k + i] = (x - y + P) % P;
				}
			}
		}
		if (op == -1) {
			reverse(s + 1, s + bit);
			int inv = fastpow(bit, P - 2);
			for (int i = 0; i < bit; i++)s[i] = 1LL * s[i] * inv%P;
		}
	}
	int solve(int *aa, int nn, int *bb, int mm, int *c) {
		n = nn; m = mm;
		bit = bitnum = 0;
		for (int i = 0; i <= n; i++) a[i] = aa[i];
		for (int i = 0; i <= m; i++) b[i] = bb[i];
		m += n;
		for (bit = 1; bit <= m; bit <<= 1)bitnum++;
		getrev(bitnum);
		NTT(a, 1);
		NTT(b, 1);
		for (int i = 0; i < bit; i++) a[i] = 1LL * a[i] * b[i] % P;
		NTT(a, -1);
		for (int i = 0; i < bit; i++) c[i] = a[i];
		for (int i = 0; i < bit; i++) a[i] = b[i] = 0;
		return bit;
	}
}

int n;
int sa[N], sum[N], pre[N], suf[N], aa[N], bb[N];

int main() {
	//freopen("0.txt", "r", stdin);
	int T; read(T);
	while (T--) {
		read(n);
		for (int i = 1; i <= n; i++) read(sa[i]);
		double ans = 0;
		for (int i = 1; i <= n; i++) {
			ans += 1LL * i * (n - i + 1) * sa[i] * sa[i];
			sum[i] = sum[i - 1] + sa[i] * sa[i];
			pre[i] = pre[i - 1] + sa[i];
		}
		for (int i = n; i >= 1; i--) suf[i] = suf[i + 1] + sa[i];
		ll r = sum[n];
		for (int len = 1; len <= n; len++) {
			ans -= r / double(len);
			int L = len + 1, R = n - len;
			if (L <= r) r += sum[R] - sum[L - 1];
			else r -= sum[L] - sum[R - 1];
		}
		for (int i = 1; i <= n; i++) {
			aa[i] = sa[i];
			bb[i] = sa[n - i + 1];
		}
		NTT::solve(aa, n + 1, bb, n + 1, aa);
		ll r1 = 0, r2 = 0;
		for (int len = 2; len <= n; len++) {
			r1 += aa[n - len + 2] - sa[n - len + 2] * suf[n - len + 3] - sa[len - 1] * pre[len - 2];
			r2 += r1;
			ans -= 2 * r2 / double(len);
		}
		printf("%.2lf\n", ans);
		for (int i = 0; i <= n + 1; i++) sum[i] = pre[i] = suf[i] = 0;
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值