(CF1316F Battalion Strength)
话说这题真的能评黑吗
Solution
先考虑暴力。
将数组排序。我们枚举 (p_i,p_j(i<j)) 为子序列中相邻的两个数,那么显然成立的概率为 (frac{1}{2^{j-i+1}}) ,那么它们对答案的贡献就是 (p_icdot p_jcdot frac{1}{2^{j-i+1}}) 。
所以答案为:
[sum_{j=2}^nsum_{i=1}^{j-1}p_icdot p_jcdot frac{1}{2^{j-i+1}}
]
时间复杂度为 (O(n^2)) 。
我们将式子拆分一下:
[sum_{j=2}^n p_jcdot frac{1}{2^{j+1}} sum_{i=1}^{j-1} p_icdot 2^i
]
后面关于 (i) 的部分,可以使用前缀和解决,时间复杂度变为 (O(n)) 。
但是本题带修,所以总复杂度为 (O(n^2)) 。
考虑使用权值线段树处理修改。
我们知道 (p_i,p_j) 的答案为 ((p_icdot 2^i) imes (p_jcdot frac{1}{2^{j+1}})) ,那么我们分别维护出区间这两个数的和即可计算答案。
线段树中纪录 (4) 个变量 (pre,suf,sum,sz) ,分别表示 (sum p_icdot frac{1}{2^{i+1}}) 、 (sum p_icdot 2^i) 、答案以及数的个数。
每次合并考虑左边对右边的贡献。
由于有相同的数,我们删除和添加不好处理,我们将相同的数拆成几个不同的区间即可。
Code
#include<bits/stdc++.h>
#define del(a,i) memset(a,i,sizeof(a))
#define ll long long
#define inl inline
#define il inl void
#define it inl int
#define ill inl ll
#define re register
#define ri re int
#define rl re ll
#define mid ((l+r)>>1)
#define lowbit(x) (x&(-x))
#define INF 0x3f3f3f3f
using namespace std;
template<class T>il read(T &x){
int f=1;char k=getchar();x=0;
for(;k>'9'||k<'0';k=getchar()) if(k=='-') f=-1;
for(;k>='0'&&k<='9';k=getchar()) x=x*10+k-'0';
x*=f;
}
template<class T>il _print(T x){
if(x>=10) _print(x/10);
putchar(x%10+'0');
}
template<class T>il print(T x){
if(x<0) putchar('-'),x=-x;
_print(x);
}
ll mul(ll a,ll b,ll mod){long double c=1.;return (a*b-(ll)(c*a*b/mod)*mod)%mod;}
it qpow(int x,int k,int mod){
int res=1,bas=x;
while(k){
if(k&1) res=1ll*res*bas%mod;
bas=1ll*bas*bas%mod,k>>=1;
}
return res;
}
const int N = 3e5+5,mod = 1e9+7;
it add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
it mul(int x,int y){return 1ll*x*y%mod;}
il inc(int &x,int y){x=add(x,y);}
int n,m,p,k,val[N],bas[N],inv[N],pre[N],pos[N<<1];
struct Node{
int ty,val,pos;
}node[N<<1];
inl bool cmp1(Node x,Node y){return x.val<y.val;}
inl bool cmp2(Node x,Node y){return x.ty<y.ty;}
struct Seg_Tree{
int pre,suf,sum,sz;
}T[N<<3];
#define lc (cur<<1)
#define rc (cur<<1|1)
il pushup(int cur){
T[cur].sz=T[lc].sz+T[rc].sz;
T[cur].pre=add(T[lc].pre,mul(T[rc].pre,bas[T[lc].sz]));
T[cur].suf=add(T[lc].suf,mul(T[rc].suf,inv[T[lc].sz]));
T[cur].sum=add(add(T[lc].sum,T[rc].sum),mul(mul(T[lc].pre,T[rc].suf),inv[T[lc].sz]));
}
il Updata(int cur,int l,int r,int pos,int s1,int s2){
if(l==r){
T[cur].pre=s1,T[cur].suf=s2,T[cur].sz=1,T[cur].sum=0;
return ;
}
if(mid>=pos) Updata(lc,l,mid,pos,s1,s2);
else Updata(rc,mid+1,r,pos,s1,s2);
pushup(cur);
}
il Delete(int cur,int l,int r,int pos){
if(l==r){
T[cur].pre=T[cur].suf=T[cur].sum,T[cur].sz=0;
return ;
}
if(mid>=pos) Delete(lc,l,mid,pos);
else Delete(rc,mid+1,r,pos);
pushup(cur);
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n),bas[0]=1;
for(ri i=1;i<=n;++i) bas[i]=mul(bas[i-1],2);
for(ri i=1;i<=n;++i) read(val[i]),node[i]=(Node){i,val[i],0};
read(m),inv[n]=qpow(bas[n],mod-2,mod);
for(ri i=n-1;i>=0;--i) inv[i]=mul(inv[i+1],2);
for(ri i=1;i<=m;++i){
read(p),read(k);
node[i+n]=(Node){n+i,k,p};
}
sort(node+1,node+1+n+m,cmp1);
for(ri i=1;i<=n+m;++i) pos[node[i].ty]=i;
sort(node+1,node+1+n+m,cmp2);
for(ri i=1;i<=n;++i) Updata(1,1,n+m,pos[i],mul(val[i],2),mul(val[i],inv[2])),pre[i]=pos[i];
printf("%d
",T[1].sum);
for(ri i=1;i<=m;++i){
p=node[i+n].pos,k=node[i+n].val;
Delete(1,1,n+m,pre[p]);
Updata(1,1,n+m,pos[i+n],mul(k,2),mul(k,inv[2])),pre[p]=pos[i+n];
printf("%d
",T[1].sum);
}
return 0;
}