CF1316F Battalion Strength
\(CF1316F Battalion Strength\)
话说这题真的能评黑吗
Solution
先考虑暴力。
将数组排序。我们枚举 \(p_i,p_j(i<j)\) 为子序列中相邻的两个数,那么显然成立的概率为 \(\frac{1}{2^{j-i+1}}\) ,那么它们对答案的贡献就是 \(p_i\cdot p_j\cdot \frac{1}{2^{j-i+1}}\) 。
所以答案为:
\[\sum_{j=2}^n\sum_{i=1}^{j-1}p_i\cdot p_j\cdot \frac{1}{2^{j-i+1}}
\]
时间复杂度为 \(O(n^2)\) 。
我们将式子拆分一下:
\[\sum_{j=2}^n p_j\cdot \frac{1}{2^{j+1}} \sum_{i=1}^{j-1} p_i\cdot 2^i
\]
后面关于 \(i\) 的部分,可以使用前缀和解决,时间复杂度变为 \(O(n)\) 。
但是本题带修,所以总复杂度为 \(O(n^2)\) 。
考虑使用权值线段树处理修改。
我们知道 \(p_i,p_j\) 的答案为 \((p_i\cdot 2^i)\times (p_j\cdot \frac{1}{2^{j+1}})\) ,那么我们分别维护出区间这两个数的和即可计算答案。
线段树中纪录 \(4\) 个变量 \(pre,suf,sum,sz\) ,分别表示 \(\sum p_i\cdot \frac{1}{2^{i+1}}\) 、 \(\sum p_i\cdot 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\n",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\n",T[1].sum);
}
return 0;
}