NOIP模拟赛 队爷的新书

队爷的新书

问题描述

队爷即将出版新书,以记录他辉煌的虐题生涯。。。
有 n 家出版社对这本书表示了兴趣,并愿意给队爷支付 p∈[Min_pay,Max_pay]的报酬来得到这本书的出版权,每家出版社的Min_pay 和 Max_pay 是不一样的。
现在队爷希望你帮他找出一个报酬值 p,使得他获得的总报酬最多。(每一个 Min_pay<=p<=Max_pay 的出版社都会付给队爷 p的报酬)

输入文件

第一行为一个整数 n。
接下来 n 行每行 2 个整数 Min_payi 和 Max_payi,为第 i 家出版社愿支付的报酬范围。

输出文件

只有一个整数 ans,为最大总报酬。
3

输入样例

4
1 3
2 4
3 5
4 7

输出样例

12

样例解释

当 p=4 时,有 3 家出版社会给出报酬,此时最大。

数据规模与约定

对于 20%的数据,1<= Min_pay,Max_pay<=10000;
对于 40%的数据,1<=n<=1000,1<= Min_pay,Max_pay<=10^6;
对于 100%的数据,1<=n<=100000,1<= Min_pay,Max_pay<=10^9。

分析

因为这是闭区间,最后的答案一定在区间端点上,其实这个和刘汝佳书上的扫描线法很像,把左右端点看成一个事件,只有遇到端点时,答案才会变化,由于这个是闭区间所以遇到端点答案是会增加的,所以两个端点(不一定非得是左右端点)之间的点一定没有端点优。其实可以换一个思路想,其实每个区间都会给区间的每一个点的权值增加1,由于是单点查询,所以就可以用差分维护。但max_pay太大了,就可以对区间左右的端点离散化之后差分。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200010;
inline int read(){
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,t[N],tot,s[N]; long long ans;
struct node{
    int x,y;
}a[N],b[N];
int main(){
    n=read();
    for(int i=1;i<=n;++i){
        a[i].x=read();a[i].y=read();
        t[++tot]=a[i].x; t[++tot]=a[i].y;
    }
    sort(t+1,t+2*n+1);
    int m=unique(t+1,t+2*n+1)-(t+1);
    for(int i=1;i<=n;++i){
        b[i].x=lower_bound(t+1,t+m+1,a[i].x)-t;
        b[i].y=lower_bound(t+1,t+m+1,a[i].y)-t;
    }
    for(int i=1;i<=n;++i)
    ++s[b[i].x],--s[b[i].y+1];
    for(int i=1;i<=m;++i) s[i]+=s[i-1];
    for(int i=1;i<=m;++i)
    if(s[i]*1ll*t[i]>ans) ans=s[i]*1ll*t[i];
    printf("%lld
",ans);
    return 0;
}
    
原文地址:https://www.cnblogs.com/huihao/p/7786449.html