• [题解] CF1316F Battalion Strength


    题意

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

    (S) 有序,求

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

    的期望,支持修改。

    (n, q le 3 imes 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('
    ');
    	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('
    ');
    	}
    	return 0;
    }
    
  • 相关阅读:
    与平面和空间打交道的计算几何
    借助水流解决问题的网络流
    计算几何算法概览
    关于while (~scanf("%d %d", &m, &n))的用法
    Minimizing maximizer(POJ 1769)
    java九九乘法表
    java替换字符串中的World为Money
    java截取字符串,第4位以后的字符串用*代替
    java使用valueOf的方法反转字符串输出
    java使用StringBuilder的方法反转字符串输出
  • 原文地址:https://www.cnblogs.com/RiverHamster/p/12451836.html
Copyright © 2020-2023  润新知