zoukankan      html  css  js  c++  java
  • 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))=Eleft( sum_{i=1}^n s_i p_i ight)=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
    ",ans);
        return 0;
    }
    带权排序
  • 相关阅读:
    如何在mysql客户端即mysql提示符下执行操作系统命令
    干掉safedog命令
    面试题-----判断两个无环单链表是否交叉,如果交叉返回交叉点
    面试题-----单链表的反转
    面试题-----ICMP协议简介
    面试题-------SSL协议简介
    面试题-----求单链表的倒数第k个节点
    面试题---两个有序单链表的合并
    面试题---求一个串中的最大连续递增数字串
    面试题---两个大整数相乘
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/13435481.html
Copyright © 2011-2022 走看看