zoukankan      html  css  js  c++  java
  • 洛谷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 }
  • 相关阅读:
    1、搭建CICD平台
    Jackson 的 基本用法
    多种方式实现动态替换Android默认桌面Launcher
    Springboot2.x整合Redis以及连接哨兵模式/集群模式
    Redis哨兵(Sentinel)模式
    redis的哨兵模式(redis有密码)
    【数据结构】——LCT(link cut tree)
    征战蓝桥 —— 2017年第八届 —— C/C++A组第3题——魔方状态
    征战蓝桥 —— 2017年第八届 —— C/C++A组第4题——方格分割
    征战蓝桥 —— 2017年第八届 —— C/C++A组第4题——方格分割
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9800448.html
Copyright © 2011-2022 走看看