洛谷P2221 [HAOI2012]高速公路(线段树+概率期望)

传送门

首先,答案等于$$ans=sum_{i=l}^rsum_{j=i}^rfrac{sum(i,j)}{C_{r-l+1}^2}$$

也就是说所有情况的和除以总的情况数

因为这是一条链,我们可以把边也转化成一个序列,用$i$表示$(i,i+1)$这一条边,那么只要把区间的右端点减一即可

。发现下面的$C_{r-l+1}^2$很好计算,考虑怎么计算上面的,转化,我们考虑每条边会被算多少次,那么答案变成$$sum_{i=l}^rsum_{j=i}^r{sum(i,j)}=sum_{i=l}^rw_i(i-l+1)(r-i+1)$$

也就是说左端点取遍这条边左边的所有点,右端点也取遍右边的所有点

化简之后可以得到$$(r+1)(1-l)sum w_i+(l+r)w_i*i-sum w_i*i^2$$

然后用线段树维护即可

ps:$sum w_i$很好维护,$sum w_i*i$在区间加的时候用等差数列求和公式计算贡献,$sum w_i*i^2$用公式$sum_{i=1}^n i^2=frac{(2n+1)n(n+1)}{6}$计算前缀和再相减来考虑贡献

pps:因为区间的右端点减一了,所以组合数应该变成$C_{r-l+2}^2$

 1 //minamoto
 2 #include<bits/stdc++.h>
 3 #define ll long long
 4 using namespace std;
 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 6 char buf[1<<21],*p1=buf,*p2=buf;
 7 inline int read(){
 8     #define num ch-'0'
 9     char ch;bool flag=0;int res;
10     while(!isdigit(ch=getc()))
11     (ch=='-')&&(flag=true);
12     for(res=num;isdigit(ch=getc());res=res*10+num);
13     (flag)&&(res=-res);
14     #undef num
15     return res;
16 }
17 inline char getop(){
18     char ch;while((ch=getc())!='C'&&ch!='Q');return ch;
19 }
20 char sr[1<<21],z[20];int C=-1,Z;
21 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
22 inline void print(ll x){
23     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
24     while(z[++Z]=x%10+48,x/=10);
25     while(sr[++C]=z[Z],--Z);sr[++C]='
';
26 }
27 const int N=1e5+5;
28 inline ll gcd(ll a,ll b){
29     if(!b) return a;
30     while(b^=a^=b^=a%=b);
31     return a;
32 }
33 inline ll calc(int x){return 1ll*(x<<1|1)*x*(x+1)/6;}
34 int n,m,tag[N<<2];ll sum[N<<2][3];
35 #define ls (p<<1)
36 #define rs (p<<1|1)
37 inline void upd(int p){for(int i=0;i<3;++i)sum[p][i]=sum[ls][i]+sum[rs][i];}
38 inline void ppd(int p,int l,int r,int w){
39     int x=r-l+1;tag[p]+=w;
40     sum[p][0]+=1ll*x*w;
41     sum[p][1]+=1ll*x*w*(l+r)>>1;
42     sum[p][2]+=1ll*w*(calc(r)-calc(l-1));
43 }
44 inline void pd(int p,int l,int r){
45     int mid=(l+r)>>1,w=tag[p];tag[p]=0;
46     ppd(ls,l,mid,w),ppd(rs,mid+1,r,w);
47 }
48 void update(int p,int l,int r,int ql,int qr,int w){
49     if(ql<=l&&qr>=r) return ppd(p,l,r,w);
50     int mid=(l+r)>>1;if(tag[p]) pd(p,l,r);
51     if(ql<=mid) update(ls,l,mid,ql,qr,w);
52     if(qr>mid) update(rs,mid+1,r,ql,qr,w);
53     upd(p);
54 }
55 ll query(int p,int l,int r,int ql,int qr,int t){
56     if(ql<=l&&qr>=r) return sum[p][t];
57     int mid=(l+r)>>1;ll res=0;if(tag[p]) pd(p,l,r);
58     if(ql<=mid) res+=query(ls,l,mid,ql,qr,t);
59     if(qr>mid) res+=query(rs,mid+1,r,ql,qr,t);
60     return res;
61 }
62 int main(){
63 //    freopen("testdata.in","r",stdin);
64     n=read(),m=read();--n;ll x,y,g;
65     while(m--){
66         char op=getop();int l=read(),r=read();--r;
67         if(op=='C') x=read(),update(1,1,n,l,r,x);
68         else{
69             y=1ll*(r-l+2)*(r-l+1)>>1;
70             x=query(1,1,n,l,r,0)*(r+1)*(1-l)+query(1,1,n,l,r,1)*(l+r)-query(1,1,n,l,r,2);
71             g=gcd(x,y);print(x/g),sr[C]='/',print(y/g);
72         }
73     }
74     return Ot(),0;
75 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9800448.html