JZOJ5232 带权排序
Description
WWT刚学会了归并排序。他在书上了解到,归并排序是一个稳定的排序算 法,也就是说,假如在原序列中,$a_i=a_j$且$i<j$,令$p_i$表示排序后$i$的位置,那 么满足$p_i<p_j$。 WWT自作主张地给每个位置$i$设定了权值$s_i$。对于一个长度为$n$的序列$A$, WWT先用归并排序给$A$排序,并得到$p_i$。令$f(A)$=$\sum_{i=1}^n s_ip_i$,WWT称$f(A)$为$A$的魅 力值。 WWT已经学会了怎么在给定$A$的情况下,求出$f(A)$。他在思考一个更为深 奥的哲学问题。假如$A$的每个元素$A_i$是随机的,那么$E[f(A)]$会是多少呢? 具体而言,$A_i$的取值是$[l_i,r_i]这个闭区间中的随机整数,即$A_i$会等概率地 等于区间中的任一整数。WWT想求出在这个条件下,$f(A)$的期望会是多少?
Solution
$$E(f(A))=E\left( \sum_{i=1}^n s_i p_i \right)=\sum_{i=1}^n s_iE(p_i)$$
令$f_i$为所有比$i$小的数的个数,则有
$$E(f(A))=\sum_{i=1}^n s_i f_i + \sum_{i=1}^n s_i$$
$$E(f_i)=\sum_{j< i} P(a_j \leq a_i) + \sum_{j> i} P(a_j < a_i)$$
讨论$\sum_{j< i} P(a_j \leq a_i)$的求解
当$l_j \leq a_i= x \leq r_j$时,$a_j$在$[l_j,x]$取值有贡献,所以$P(a_j \leq a_i)=\frac{x-l_j+1}{r_j-l_j+1}$
当$r_j < x$时,$a_j$总有贡献,所以$P(a_j \leq a_i)=1$
那么发现贡献总是能写成等差数列的形式,使用动态开点线段树维护,以取值为下标,维护区间求和和区间修改的操作
注意在线段树上区间加等差数列的操作
#pragma GCC optimize(2) #include<iostream> #include<cstdio> using namespace std; long long n,s[100005],l[100005],r[100005],ans,tot,root; const long long mod=1000000007; struct Tree { long long ls,rs,A1,d,sum; }tree[10000005]; inline long long read() { long long f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') { f=-1; } ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } long long ksm(long long a,long long p) { long long ret=1ll; while(p) { if(p&1) { (ret*=a)%=mod; } (a*=a)%=mod; p>>=1; } return ret; } void pushdown(long long i,long long l,long long r) { if(tree[i].A1||tree[i].d) { if(l!=r) { if(!tree[i].ls) { tree[i].ls=++tot; } if(!tree[i].rs) { tree[i].rs=++tot; } long long mid=l+r>>1; (tree[tree[i].ls].A1+=tree[i].A1)%=mod; (tree[tree[i].rs].A1+=(mid+1-l)*tree[i].d+tree[i].A1)%=mod; (tree[tree[i].ls].d+=tree[i].d)%=mod; (tree[tree[i].rs].d+=tree[i].d)%=mod; } (tree[i].sum+=(tree[i].A1+tree[i].A1+tree[i].d*(r-l)%mod)*(r-l+1)%mod*500000004ll%mod)%=mod; tree[i].A1=tree[i].d=0; } } long long query(long long &i,long long l,long long r,long long L,long long R) { if(!i) { return 0; } pushdown(i,l,r); if(L<=l&&r<=R) { return tree[i].sum; } long long mid=l+r>>1,ret=0; if(L<=mid) { (ret+=query(tree[i].ls,l,mid,L,R))%=mod; } if(R>mid) { (ret+=query(tree[i].rs,mid+1,r,L,R))%=mod; } return ret; } void update(long long &i,long long l,long long r,long long L,long long R,long long v1,long long v2) { if(!i) { i=++tot; } pushdown(i,l,r); if(L<=l&&r<=R) { (tree[i].A1+=(l-L)*v2%mod+v1)%=mod; (tree[i].d+=v2)%=mod; return; } long long mid=l+r>>1; if(L<=mid) { update(tree[i].ls,l,mid,L,R,v1,v2); } if(R>mid) { update(tree[i].rs,mid+1,r,L,R,v1,v2); } pushdown(tree[i].ls,l,mid); pushdown(tree[i].rs,mid+1,r); tree[i].sum=(tree[tree[i].ls].sum+tree[tree[i].rs].sum)%mod; } int main() { n=read(); for(long long i=1;i<=n;i++) { s[i]=read(); (ans+=s[i])%=mod; l[i]=read(); r[i]=read(); long long temp=ksm(r[i]-l[i]+1,mod-2); (ans+=query(root,0,1000000000,l[i],r[i])*temp%mod*s[i]%mod)%=mod; update(root,0,1000000000,l[i],r[i],temp,temp); update(root,0,1000000000,r[i]+1,1000000000,1,0); } for(long long i=0;i<=tot;i++) { tree[i].A1=tree[i].d=tree[i].rs=tree[i].ls=tree[i].sum=0; } tot=0; root=0; for(long long i=n;i>=1;i--) { long long temp=ksm(r[i]-l[i]+1,mod-2); (ans+=query(root,0,1000000000,l[i],r[i])*temp%mod*s[i]%mod)%=mod; update(root,0,1000000000,l[i],r[i],0,temp); update(root,0,1000000000,r[i]+1,1000000000,1,0); } printf("%lld\n",ans); return 0; }