题目链接:传送门
题意&分析转自BESTCODER:
首先分母就是
C(m,3)C(m,3)C(m,3),考虑如何计算分子。
注意到期望的独立性,我们可以首先用O(n+m)O(n+m)O(n+m)的时间利用差分前缀和预处理出每个点被几个区间覆盖,假设第iii个点被sis_isi个区间所覆盖,那么第iii个点对分子的贡献即为wi×C(si,3)w_i\times C(s_i,3)wi×C(si,3),注意不要爆long long。
我用树状数组统计了每个点被覆盖的的次数剩下的就按照题解的搞
树状数组几种常见的用法的分类传送门
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; const int maxn = 1e5+10; typedef long long LL; LL sum[maxn]; int a[maxn]; void init(){ memset(sum,0,sizeof(sum)); } int lowbit(int x){ return x&(-x); } LL n,m; void update(int pos,int val){ while(pos>0){ sum[pos]+=val; pos-=lowbit(pos); } } LL get(int pos){ LL ans = 0; while(pos<=n){ ans = ans+sum[pos]; pos+=lowbit(pos); } return ans; } LL gcd(LL a,LL b){ if(b) return gcd(b,a%b); return a; } int main() { int t; scanf("%d",&t); while(t--){ init(); scanf("%I64d%I64d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=0;i<m;i++){ int l,r; scanf("%d%d",&l,&r); update(r,1); update(l-1,-1); } LL tot = 0; for(int i=1;i<=n;i++){ LL tmp = get(i); if(tmp>=2) tot=tot+tmp*(tmp-1)*(tmp-2)/6*(LL)a[i]; } LL tt = (LL)m*(LL)(m-1)*(LL)(m-2)/6; LL tmp = gcd(tot,tt); if(tmp==0){ puts("0"); continue; } if(tt==tmp) printf("%I64d\n",tot/tmp); else printf("%I64d/%I64d\n",tot/tmp,tt/tmp); } return 0; }