【NOIP2017模拟A组模拟8.5】带权排序

30 篇文章 0 订阅
7 篇文章 0 订阅

Description

这里写图片描述

Input

输入文件名为sort.in。
第一行包含一个整数n。
接下来n行,每行三个整数si,li,ri,表示Ai的值为[li,ri] 中的随机整数。

Output

输出文件名为sort.out。
输出一个整数,表示答案。

Sample Input

输入1:
4
1 2 3
4 4 6
2 0 5
3 2 6

输入2:
10
53736 68 512
82493 870 920
77300 206 576
63900 4 565
68675 0 488
13610 4 922
57472 614 825
37474 394 970
51896 398 766
77136 656 723

Sample Output

输出1:
650000033

输出2:
743178372

Data Constraint

对于20%的数据,n<=6,0<=li<=ri<=15
对于40%的数据,n<=10,0<=li<=ri<=20
对于60%的数据,0<=li<=ri<=1000
对于100%的数据,n<=10^5,0<=li<=ri<=10^9,0<=si<=10^9

Solution

这些题脑洞怎么这么大

ans=E[f(A)]=E[i=1ns[i]p[i]]=i=1ns[i]E[p[i]]

考虑求 E[p[i]]
可以知道,位置i的取值是l[i]~r[i]
假设取x
那么考虑一个位置 j(j<i)
假设 r[j]<=x ,那么j对i取x时的贡献为1(这些贡献都要 /(r[i]l[i]+1) 这里省略)
假设 l[j]>x ,那么j对i取x时的贡献为0
假设 l[j]<=x<=r[j] ,那么j对i取x时的贡献为 xl[j]+1r[j]l[j]+1

考虑一个位置 j(j>i)
假设 r[j]<x ,那么j对i取x时的贡献为1(这些贡献都要 /(r[i]l[i]+1) 这里省略)
假设 l[j]>x ,那么j对i取x时的贡献为0
假设 l[j]<x<r[j] ,那么j对i取x时的贡献为 xl[j]r[j]l[j]+1


如果通过枚举x的方法来做,可以得60分
再发现一些东西
考虑位置j对位置i的贡献 (j<i) 反过来同理
再看i取x时
贡献为 xl[j]+1r[j]l[j]+1
那么i取每个数的贡献就是 r[i]x=l[i]xl[j]+1r[j]l[j]+1
在一个数轴上,如果将l[j]~r[j]的地方每个位置x加上 xl[j]+1r[j]l[j]+1 ,就是加上一个等差数列,在r[j]+1~n的每个位置+1,那么j对i的贡献是不是就是数轴上l[i]~r[i]的和
这个数轴可以通过线段树来维护,等差数列也是可以合并的
因为等差数列一定加在整个区间上,所以等差数列只需维护初始值(首项)s和公差t
那么两个等差数列s1t1和s2t2合并后,初始值就是s1+s2,公差就是t1+t2

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(ll i=a;i<=b;i++)
#define fd(i,a,b) for(ll i=a;i>=b;i--)
#define N 1010000
#define ll long long
#define mo 1000000007
using namespace std;
int l[N],r[N],s[N],n,mx=0,tot=1;
ll ans,p[N],ny2;
struct node{
    int l,r;
    ll sum,s,t;
}t[N*10];
ll mi(ll a,ll b)
{
    if(b==0) return 1;
    if(b==1) return a;
    ll k=mi(a,b/2);
    k=(k*k)%mo;
    if(b%2==1) k=(k*a)%mo;
    return k;
}
ll calc(ll a,ll b,ll c)
{
    return (((((b+b+(a-1)*c)%mo)*a)%mo)*ny2)%mo;
}
void down(int v,ll i,ll j,ll m)
{
    t[v].l=t[v].l==0?++tot:t[v].l;
    t[v].r=t[v].r==0?++tot:t[v].r;
    (t[t[v].l].sum+=calc(m-i+1,t[v].s,t[v].t))%=mo;
    (t[t[v].r].sum+=calc(j-m,(t[v].s+(m-i+1)*t[v].t)%mo,t[v].t))%=mo;
    (t[t[v].l].s+=t[v].s)%=mo;(t[t[v].l].t+=t[v].t)%=mo;
    (t[t[v].r].s+=(t[v].s+(m-i+1)*t[v].t)%mo)%=mo;(t[t[v].r].t+=t[v].t)%=mo;
    t[v].s=t[v].t=0;
}
ll get(int v,int i,int j,ll l,ll r)                                                                                                                                                                             
{
    if(v==0) return 0;
    if(i==l&&j==r) return t[v].sum;
    ll m=(i+j)/2;down(v,i,j,m);
    if(r<=m) return get(t[v].l,i,m,l,r);
    else if(l>m) return get(t[v].r,m+1,j,l,r);
         else return (get(t[v].l,i,m,l,m)+get(t[v].r,m+1,j,m+1,r))%mo;
}
void ins(int v,int i,int j,ll l,ll r,ll z,ll e)
{
    if(i==l&&j==r)
    {
        (t[v].sum+=calc(r-l+1,z,e))%=mo;
        (t[v].s+=z)%=mo;(t[v].t+=e)%=mo;
        return;
    }
    ll m=(i+j)/2;down(v,i,j,m);
    if(r<=m) ins(t[v].l,i,m,l,r,z,e);
    else if(l>m) ins(t[v].r,m+1,j,l,r,z,e);
         else ins(t[v].l,i,m,l,m,z,e),ins(t[v].r,m+1,j,m+1,r,(z+(m-l+1)*e)%mo,e);
    t[v].sum=(t[t[v].l].sum+t[t[v].r].sum)%mo;   
}
void read(int &x)
{
    char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar());
    x=0;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-48;
}
int main()
{
    freopen("sort.in","r",stdin);
    freopen("sort.out","w",stdout);
    ny2=mi(2,mo-2);
    scanf("%d",&n);
    fo(i,1,n) read(s[i]),read(l[i]),read(r[i]),l[i]++,r[i]++,mx=max(mx,r[i]);
    mx++;
    fo(i,1,n)
    {
        ll ny=mi(r[i]-l[i]+1,mo-2);
        p[i]=1+get(1,1,mx,l[i],r[i])*ny%mo;
        ins(1,1,mx,l[i],r[i],ny,ny);
        ins(1,1,mx,r[i]+1,mx,1,0);
    }
    memset(t,0,sizeof(t));
    tot=1;
    fd(i,n,1)
    {
        ll ny=mi(r[i]-l[i]+1,mo-2);
        p[i]=(p[i]+get(1,1,mx,l[i],r[i])*ny)%mo;
        if(l[i]<r[i]) ins(1,1,mx,l[i]+1,r[i],ny,ny);
        ins(1,1,mx,r[i]+1,mx,1,0);
    }
    fo(i,1,n) (ans+=(p[i]*(ll)s[i])%mo)%=mo;
    printf("%lld",ans);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值