其他分享
首页 > 其他分享> > [usaco2010 Oct]Soda Machine

[usaco2010 Oct]Soda Machine

作者:互联网

题目描述

有N个人要去膜拜JZ,他们不知道JZ会出现在哪里,因此每个人有一个活动范围,只要JZ出现在这个范围内就能被膜拜, 伟大的JZ当然希望膜拜他的人越多越好,但是JZ不能分身,因此只能选择一个位置出现,他最多可以被多少人膜拜呢, 这个简单的问题JZ当然交给你了

输入格式

Line 1: A single integer: N (1 <= N <= 50,000)

Lines 2..N+1: Line i+1 contains two space-separated integers: A_i and B_i (1 <= A_i <= B_i; A_i <= B_i <= 1,000,000,000)

输出格式

Line 1: A single integer representing the largest number of cows whose grazing intervals can all contain the soda machine.


考虑暴力。

暴力当然是循环Ai到Bi然后把每个数都加起来啦~时间复杂度为O(N * Max(Bi))

既然是区间上的修改问题,我们可以想想线段树的做法。

每次用线段树修改Ai到Bi之间的区间的权值,然后查询1~Max(Bi)之间的最大值即可。时间复杂度为O(N * logMax(Bi))。似乎能跑得过诶。但数组根本开不下好吗?!

转变一下思路。设c[i]表示第i个位置可能有的膜拜JZ的人数,那么为了完成题目,我们需要对于每个Ai和Bi:

Ai~Bi之间的每个位置的前缀和都加一,但又不能Bi影响后面的地方。很容易想到用差分来做这题。对于每个Ai和Bi,我们可以:c[Ai]++,c[Bi+1]--。然后计算前缀和,最大的前缀和就是答案了。时间复杂度为O(N+Max(Bi))。但还是存在数组开不下的位置。

不同于之前的线段树做法,用差分做的时候就只用到了所有Ai和Bi的位置,其它地方的数组相当于浪费了。所以我们可以对所有位置离散化。那么时间复杂度就变成了可以接受的O(2 * NlogN+2 * N)≈O(NlogN)。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#define maxn 50001
using namespace std;

map<int,int> mp;
int n;

inline int read(){
    register int x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}

int main(){
    n=read();
    for(register int i=1;i<=n;i++){
        int a=read(),b=read();
        mp[a]++,mp[b+1]--;
    }
    int ans=0,sum=0;
    for(map<int,int>::iterator it=mp.begin();it!=mp.end();it++){
        sum+=(*it).second;
        if(sum>ans) ans=sum;
    }
    cout<<ans<<endl;
    return 0;
}

标签:JZ,Ai,膜拜,Bi,Machine,复杂度,Soda,include,Oct
来源: https://www.cnblogs.com/akura/p/10908099.html