[题解] CF1316F Battalion Strength

题意

给定序列 \(a\),现在在 \(a\) 中随机选出一个可重集 \(S\)

\(S\) 有序,求

\[\sum_{i=1}^{|S|-1} S_i S_{i+1} \]

的期望,支持修改。

\(n, q \le 3 \times 10^5\)

思路

首先集合数是 \(2^n\) ,转成数数。

然后发现求和之间没有什么关系,考虑对于每个 pair 计算贡献,即 \(2^{n - (i-j+1)} a_i a_j\),其中 \(\{a\}\) 有序

如果不带修改,这个用个前/后缀和维护就好。

支持修改的维护比较麻烦,但仔细想发现可以在线段树上直接维护,利用权值线段树将一个区间分成两个的特点分治维护。

对于每个线段树节点维护 \(size\)\(a_i \cdot 2^{i-1}\)\(a_i \cdot 2^{size-i}\) 和答案即可。

合并信息非常容易,对于叶子节点可能一个数字出现多次的情况,可以预处理同一个值的贡献次数,具体参见代码。(不过我这码风不能看啊)

Code

想清楚,实现并不难,不要拿到就写啊。

貌似有个 pypy 跑的比我快???

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
typedef long long ll;
namespace io {
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	char getc () {return gc();}
	inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
	inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
	template <class I> inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
	template <class I> inline void print (I x) {if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while (x) qu[++ qr] = x % 10 + '0',  x /= 10;while (qr) putc (qu[qr --]);}
	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: gi; using io :: putc; using io :: print; using io :: getc;
template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
template<class T> void upmin(T &x, T y){x = x<y ? x : y;}

const int mod = 1000000007;
inline int add(int x, int y){return x+y>=mod ? x+y-mod : x+y;}
inline int sub(int x, int y){return x-y<0 ? x-y+mod : x-y;}
inline int mul(int x, int y){return 1LL * x * y % mod;}
inline int power(int x, int y){
	int res = 1;
	for(; y; y>>=1, x = mul(x, x)) if(y & 1) res = mul(res, x);
	return res;
}
inline int inv(int x){return power(x, mod - 2);}

const int N = 300005, Node = 2400005;
int p[N];
int pow2[N];
int n, q;

int v[N * 2], vc = 0;
int pos[N], val[N], single[N];
#define Rt 1, 1, vc

int pre[Node], suf[Node], sum[Node], sz[Node];
void modify(int x, int l, int r, int p, int d){
	if(l == r){
		sz[x] += d;
		sum[x] = mul(mul(v[p], v[p]), single[sz[x]]);
		if(d == 1) pre[x] = add(pre[x], mul(v[p], pow2[sz[x] - 1])), suf[x] = add(suf[x], mul(v[p], pow2[sz[x] - 1]));
		else pre[x] = sub(pre[x], mul(v[p], pow2[sz[x]])), suf[x] = sub(suf[x], mul(v[p], pow2[sz[x]]));
		return ;
	}
	int mid = (l + r) >> 1;
	p <= mid ? modify(x << 1, l, mid, p, d) : modify(x << 1 | 1, mid + 1, r, p, d);
	sz[x] = sz[x << 1] + sz[x << 1 | 1];
	pre[x] = add(pre[x << 1], mul(pow2[sz[x << 1]], pre[x << 1 | 1]));
	suf[x] = add(suf[x << 1 | 1], mul(pow2[sz[x << 1 | 1]], suf[x << 1]));
	sum[x] = add(add(mul(sum[x << 1], pow2[sz[x << 1 | 1]]), mul(sum[x << 1 | 1], pow2[sz[x << 1]])), mul(pre[x << 1], suf[x << 1 | 1])); // 信息合并
}
#define Rt 1, 1, vc

int main(){
	int allinv;
	gi(n);
	pow2[0] = 1;
	for(int i=1; i<=n; i++)
		pow2[i] = add(pow2[i-1], pow2[i-1]);
	for(int i=2; i<=n; i++)
		single[i] = add(add(single[i-1], single[i-1]), sub(pow2[i - 1], 1)); // 单点贡献
	allinv = inv(pow2[n]);
	for(int i=1; i<=n; i++) gi(p[i]), v[++vc] = p[i];
	gi(q);
	for(int i=1; i<=q; i++){
		gi(pos[i]); gi(val[i]);
		v[++vc] = val[i];
	}
	sort(v+1, v+1+vc);
	vc = unique(v+1, v+1+vc) - v - 1;
	for(int i=1; i<=n; i++){
		p[i] = lower_bound(v+1, v+1+vc, p[i]) - v;
		modify(Rt, p[i], 1);
	}
	print(mul(sum[1], allinv)); putc('\n');
	for(int i=1; i<=q; i++){
		val[i] = lower_bound(v+1, v+1+vc, val[i]) - v;
		modify(Rt, p[pos[i]], -1);
		modify(Rt, val[i], 1);
		p[pos[i]] = val[i];
		print(mul(sum[1], allinv)); putc('\n');
	}
	return 0;
}
posted @ 2020-03-09 21:50  RiverHamster  阅读(127)  评论(0编辑  收藏  举报
\