多的不说,看题:
一、游客运输
风景迷人的阆中市,拥有n个美丽景点,编号为1..n。由于慕名而来的游客越来越多,市政府特意安排了一辆容量为C的观光公交车,为游客提供便捷的交通服务。观光公交每天早上从1号景点出发,一次前往2,3,…n号景点,每天只开一趟。
设某天有m位游客,每位乘车1次,第i位游客希望从景点Li到达景点Ri(1<=Li<=Ri<=n)。
现在给你观光公交的容量C,同事提供给你每位乘客的信息,请你计算这一天中最多能满足都少个人的愿望。
【输入格式】
第一行包含两个整数n,m,C,分别表示景点数目、游客数目和观光公交的容量。
第2行到第m+1行,每行包含两个整数:Li,Ri,其中第i+1行表示奶牛i想从景点Li到达Ri。
【输出格式】
一个整数,表示能满足的游客数量。
【输入样例】
10 8 3
8 10
1 9
2 10
6 8
5 8
6 7
3 5
4 6
【输出样例】
6
【数据范围】
n,m,C<=200000
观察到乘客的区间是一条线段,左右端点有一定的先后顺序。
可以考虑按某一端点排序之后贪心计算;
对于一个乘客,如果有空位,就直接坐
如果没有空位,可以替换一个要做更久的人
想象一列火车从左向右开,乘客依次上车;到了没有位置的时候,这时为了更好地满足后面乘客的需求,可以找一个下车时间在该乘客之后的乘客下车,然后让乘客i上车;
可以用优先队列或者是set维护。
这里用的set:
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<iostream>
#include<set>
using namespace std;
int n,m,c,ans=0;
struct ge
{
int l,r;
friend bool operator<(ge x,ge y)
{
return x.l<y.l;
}
}a[200005];
multiset<int>s;
multiset<int>::iterator it;
int main()
{
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=m;i++) scanf("%d%d",&a[i].l,&a[i].r);
sort(a+1,a+1+m);
for(int i=1;i<=m;i++)
{
if(a[i].l==a[i].r)
{
ans++;
continue;
}
it=s.begin();
while(!s.empty() && *it<=a[i].l)//删除已经下车的人
{
s.erase(it);
it=s.begin();
}
if(s.size()<c)//有空位
{
ans++;
s.insert(a[i].r);
}
else //找人替换
{
it=--s.end();
if(*it>a[i].r)
{
s.erase(it);
s.insert(a[i].r);
}
}
}
printf("%d",ans);
return 0;
}
二、奶牛航班
【问题描述】
为了表示不能输给人类,农场的奶牛们决定成立一家航空公司。他们计划每天清晨,从密歇根湖湖岸的最北段飞向最南端,晚上从最南端飞往最北端。旅途中,航空公司可以安排飞机停在某些机场,他们需要你帮助来决定每天携带那些旅客。
沿着湖岸,有N个由北到南编号为1到N的农场。每个农场都有一个机场,这填,有k群牛想要乘坐飞机旅行。每一群牛想要从一个农场飞往另一个农场,航班可以在某些农场停下来带上部分或全体牛。奶牛们登记后会一直停留直至到达目的地。
提供给你飞机的容量为C,同时提供给你想要旅行的奶牛信息,请你计算出这一天的航班最多能满足几只奶牛的愿望。
【输入格式】
第1行有3个整数:K,N,C。接下来的K行,每行包含3个整数:S,E,M,表示有M只奶牛想从农场S乘飞机到农场E。
【输出格式】
可以完成旅行的奶牛人数的最大值。
【输入样例】
4 8 3
1 3 2
2 8 3
4 7 1
8 3 2
【输出样例】
6
【样例解释】
有3群奶牛旅行,8个农场,飞机上有3个作为。造成,飞机把2只牛从1带到3,1只从2带到8,1只从4带到7.晚上,航班把2只牛从8带到3。
【数据范围】
1<=N<=10000
1<=K<=50000
1<=C<=100
当然一来一回分两次计算就行了
和上题有不同的地方在于相同路段的乘客有多个:
思路大致相同,但是这里计算容量就不能再用s.size()了,而要新开一个数组c[x]表示在x下车的乘客数量,并用now表示当前车的容量;对于每个乘客来说同样有两种情况,有空位或把人踢下车;
要注意的就是情况有点多,所以写得有点复杂。。。orz
用优先队列实现的;
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
const int maxn=50005;
const int maxm=40005;
int K,n,C,c1,c2,c[maxn],now,last,ans,l,r,s;
struct data{
int l,r,s;
friend bool operator <(data a,data b){
return a.r<b.r;
}
}t,tt,a[maxn],b[maxn];
bool cmp(data a,data b){
return a.l<b.l;
}
void work1(){
priority_queue<data>q;
sort(a+1,a+1+c1,cmp);
now=C,last=0;
for(int i=1;i<=c1;i++){
while(!q.empty() && q.top().r<=a[i].l) q.pop();
while(last<=a[i].l) now+=c[last++];
if(now){//有位置
if(now>=a[i].s){
q.push(a[i]);
now-=a[i].s;
ans+=a[i].s;
c[a[i].r]+=a[i].s;
a[i].s=0;
}
else{
q.push((data){a[i].l,a[i].r,now});
ans+=now;
a[i].s-=now;
c[a[i].r]+=now;
now=0;
}
}
if(a[i].s){//把终点在i后面的踢下去
s=0;
while(!q.empty()){
if(s<a[i].s && a[i].r<q.top().r){
if(s+q.top().s<=a[i].s){
s+=q.top().s;
c[q.top().r]-=q.top().s;
q.pop();
}
else{
t=q.top();
c[q.top().r]-=a[i].s-s;
t.s-=a[i].s-s;
s=a[i].s;
q.pop();q.push(t);
}
}
else break;
}
if(s){
q.push((data){a[i].l,a[i].r,s});
c[a[i].r]+=s;
}
}
}
}
void work2(){
memset(c,0,sizeof(c));
priority_queue<data>q;
sort(b+1,b+1+c2,cmp);
now=C,last=0;
for(int i=1;i<=c2;i++){
while(last<=b[i].l) now+=c[last++];
if(now){//有位置
if(now>=b[i].s){
q.push(b[i]);
now-=b[i].s;
ans+=b[i].s;
c[b[i].r]+=b[i].s;
b[i].s=0;
}
else{
q.push((data){b[i].l,b[i].r,now});
ans+=now;
b[i].s-=now;
c[b[i].r]+=now;
now=0;
}
}
if(b[i].s){//把终点在i后面的踢下去
s=0;
while(!q.empty() && s<b[i].s && b[i].r<q.top().r){
if(s<b[i].s && b[i].r<q.top().r){
if(s+q.top().s<=b[i].s){
s+=q.top().s;
c[q.top().r]-=q.top().s;
q.pop();
}
else{
t=q.top();
c[q.top().r]-=b[i].s-s;
t.s-=b[i].s-s;
s=b[i].s;
q.pop();q.push(t);
}
}
else break;
}
if(s){
q.push((data){b[i].l,b[i].r,s});
c[b[i].r]+=s;
}
}
}
}
char ch;
void _scanf(int &x){
x=0;
ch=getchar();
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d%d",&K,&n,&C);
ans=0,c1=c2=0;
for(int i=1;i<=K;i++){
_scanf(l);_scanf(r);_scanf(s);
if(l==r){
ans++;continue;
}
if(l<r) a[++c1]=(data){l,r,s};
else b[++c2]=(data){r,l,s};
}
work1();
work2();
printf("%d\n",ans);
return 0;
}
三、火车运输
【问题描述】
ByteLand火车站(编号0)每天都要发往全国各地N列客运火车,编号1 N。第i列火车的目的地是编号Si的火车站。
对任意车站X,都与X+1车站有铁轨直接相连,因此火车站可以看成数轴上的整数点,第i列火车可以停靠区间[0, Si]中的各个站点。每列火车装载乘客的最大容量为Ci。有M个人需要乘坐火车。已知每个人的乘车区间为[Li, Ri],即是说,在Li上车,在Ri下车。
由于火车的容量限制,请你求出最多有多少人的乘车需求可以得到满足。
【输入格式】
第1行:2个整数N和M。
接下来N行,每行2个整数Si和Ci,表示第i辆车的目的站和容量。
接下来M行,每行2个整数Li和Ri,表示第i个乘客的乘车区间。
【输出格式】
第1行:1个整数,表示最多有多少乘客的乘车需求可以满足
【输入样例】
1 3
10 2
1 5
3 7
4 9
【输出样例】
2
【数据范围】
对于20%的数据,
N= 1, 1 ≤ M ≤ 10^5
1 ≤Si,Ci ≤ 10^9
1 ≤ Li ≤ Ri ≤ 10^9。
对于另外20%的数据,
1 ≤ N,M ≤ 2000
1 ≤Si,Ci ≤ 10^9
1 ≤ Li ≤ Ri ≤ 10^9。
对于100%的数据,
1 ≤ N,M ≤ 10^5
1 ≤Si,Ci ≤ 10^9
1 ≤ Li ≤ Ri ≤ 10^9。
和二不同的是火车也有多个;
意思就是火车在不同的时间的容量是不同的?!!
但是火车有公共的起点1。我们当然不能让火车开着开着容量就减少了,这样怎么贪心计算。。。所以我们把终点看成起点,火车从终点开向起点,乘客也从终点走到起点,所以我们按照右端点从大到小排序,并从右向左枚举乘客;
对于一个(右端点靠右)乘客,我们要尽可能用右端点靠右的公交装(因为右端点稀有)
所以我们把乘客按照右端点从大到小开始枚举 (一开始把第一个公交也无法装的乘客直接删掉)
枚举每个乘客能否装在公交里;首先应将新加进队伍中的公交(bus[j].r>=pas[i].r)的容量加入now中,且由于容量是now的公交可以看成是now个容量为1的公交,所以我们可以分开考虑c个公交的情况和当前车上的人数,从而简化了模型
我们就可以更新出车的现在可用容量并把装有人的车(的目的地)甩进set中。
转换模型之后就是游客运输了;
乘客能装有两个选择:
1.有空车
2.车上的人比当前乘客下得还早(s.begin()<pas[i].l)
当然要维护当前车的总可用容量(下车)
cnt[i]记录在点i的下车人数
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
using namespace std;
const int maxn=1000005;
int n,m,cnt[maxn],last,ans,now;
struct passenger{
int l,r;
friend bool operator <(passenger a,passenger b){
if(a.r==b.r) return a.l>b.l;
return a.r>b.r;
}
}pas[maxn];
struct route{
int s,c;
friend bool operator <(route a,route b){
return a.s>b.s;
}
}bus[maxn];
multiset<int>s;
multiset<int>::iterator it;
void work(){
sort(bus+1,bus+1+n);
sort(pas+1,pas+1+m);
int i=1,j=1;
last=bus[1].s;
while(i<=m && pas[i].r>bus[1].s) i++;
for(;i<=m;i++){
while(j<=n && bus[j].s>=pas[i].r){
now+=bus[j].c,j++;
}
while(last>pas[i].r && last>0){
now+=cnt[--last];
}
if(now){
now--,cnt[pas[i].l]++,ans++;
s.insert(pas[i].l);
}
else{
it=s.begin();
if(it==s.end()) continue;
int t=*it;
if(t<pas[i].l){
cnt[t]--,cnt[pas[i].l]++;
s.erase(it);
s.insert(pas[i].l);
}
}
}
printf("%d\n",ans);
}
char ch;
void _scanf(int &x){
x=0;
ch=getchar();
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
_scanf(bus[i].s);_scanf(bus[i].c);
}
for(int i=1;i<=m;i++){
_scanf(pas[i].l);_scanf(pas[i].r);
}
work();
return 0;
}
反正就是更新状态+替换啦~