[CSP-S 2021] 廊桥分配
今日集训再回首,顿感萧瑟......(拽文自得中)
题意:有n个廊桥,确定的国内及国际飞机飞来,已知每个飞机的到达时间和离开时间,求如何分配廊桥能使接纳过的飞机最多
暴力做法
先枚举国内和国际机场所分配的廊桥,每次枚举都进行一遍查看,取最大即可——45分好成绩
#include<bits/stdc++.h> using namespace std; namespace _xzy { typedef long long ll; inline int read() { ll sm=0,flag=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')flag=-1;ch=getchar();} while(ch>='0'&&ch<='9'){sm=sm*10+ch-'0';ch=getchar();} return sm*flag; } const ll N=1e5+2; ll n,m1,m2,ans; struct node { ll get,left,id; }e[N]; int cmp(node x,node y) { return x.get<y.get; } void search(ll maxna,ll maxnb) { priority_queue<ll>qa; priority_queue<ll>qb; ll nowa=0,nowb=0,num=0; for(ll i=1;i<=m1+m2;++i) { ll time=e[i].get; while(!qa.empty()) { if(-1*qa.top()>time)break; qa.pop();nowa--; } while(!qb.empty()) { if(-1*qb.top()>time)break; qb.pop();nowb--; } if(e[i].id==1&&nowa<maxna) { nowa++;qa.push(-1*e[i].left);num++; } else if(e[i].id==2&&nowb<maxnb) { nowb++;qb.push(-1*e[i].left);num++; } } ans=max(ans,num); } void My_main() { n=read();m1=read();m2=read(); for(ll i=1;i<=m1;++i) { e[i].get=read();e[i].left=read();e[i].id=1; } for(ll i=m1+1;i<=m1+m2;++i) { e[i].get=read();e[i].left=read();e[i].id=2; } sort(e+1,e+1+m1+m2,cmp); for(ll i=0;i<=n;++i) search(i,n-i); cout<<ans; } } int main() { _xzy::My_main(); return 0; }
正解
我们从暴力分中可以发现国内机场的停靠和国际机场的停靠是互不影响的
然后我们还可以从题目中得出结论
1.每次对答案产生影响的时候,都是新飞机来的时候
2.新飞机来时,需要考虑剩余的廊桥数量,如此便需要离开时间
3.无论飞机停靠在哪个廊桥,都不会对最终的结果造成影响
然而如果飞机随便停靠的话,我们会非常头疼如何缩小时间复杂度,如果是有序的就世界都清净了。
4.我们就在飞机来时优先停靠在可停靠的编号最小的廊桥。
根据“先到先得”的题意,我们易发现5.任何一个特定的飞机只会在特定编号的廊桥停靠。
然后我们就会发现无论机场内廊桥的个数是什么,特定廊桥的到达过的飞机的数量是固定的
于是我们记录每个廊桥能到达的飞机数,做前缀和即可
#include<bits/stdc++.h> using namespace std; namespace _xzy { typedef long long ll; inline int read() { ll sm=0,flag=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')flag=-1;ch=getchar();} while(ch>='0'&&ch<='9'){sm=sm*10+ch-'0';ch=getchar();} return sm*flag; } const ll N=1e5+2; ll n,m1,m2,ans; ll ansa[N],ansb[N]; bool vis[N]; struct node { ll get,left,id; }e[N],a[N],b[N]; struct noed { ll left,id; friend bool operator < (noed a,noed b) { return a.left>b.left; } }; int cmp(node x,node y) { return x.get<y.get; } void search(ll maxna,ll maxnb) { priority_queue<ll>qa; priority_queue<ll>qb; ll nowa=0,nowb=0,num=0; for(ll i=1;i<=m1+m2;++i) { ll time=e[i].get; while(!qa.empty()) { if(-1*qa.top()>time)break; qa.pop();nowa--; } while(!qb.empty()) { if(-1*qb.top()>time)break; qb.pop();nowb--; } if(e[i].id==1&&nowa<maxna) { nowa++;qa.push(-1*e[i].left);num++; } else if(e[i].id==2&&nowb<maxnb) { nowb++;qb.push(-1*e[i].left);num++; } } ans=max(ans,num); } void prepare() { priority_queue<ll>num;//空着的廊桥 priority_queue<noed>q;//停靠的飞机 sort(a+1,a+1+m1,cmp); for(ll i=1;i<=m1;++i) num.push(-i); for(ll i=1;i<=m1;++i) { ll time=a[i].get; while(!q.empty()) { if(q.top().left>time)break; num.push(q.top().id);q.pop(); } ansa[-num.top()]++; q.push(noed{a[i].left,num.top()});num.pop(); } while(!num.empty())num.pop(); for(ll i=1;i<=m2;++i) num.push(-i); while(!q.empty())q.pop(); sort(b+1,b+1+m2,cmp); for(ll i=1;i<=m2;++i) { ll time=b[i].get; while(!q.empty()) { if(q.top().left>time)break; num.push(q.top().id);q.pop(); } ansb[-num.top()]++; q.push(noed{b[i].left,num.top()});num.pop(); } for(ll i=0;i<=n;++i) { ansa[i]+=ansa[i-1];ansb[i]+=ansb[i-1]; } } void My_main() { n=read();m1=read();m2=read(); if(n<=5000&&m1+m2<=5000) { for(ll i=1;i<=m1;++i) { e[i].get=read();e[i].left=read();e[i].id=1; } for(ll i=m1+1;i<=m1+m2;++i) { e[i].get=read();e[i].left=read();e[i].id=2; } sort(e+1,e+1+m1+m2,cmp); for(ll i=0;i<=n;++i) search(i,n-i); cout<<ans; } else { for(ll i=1;i<=m1;++i) { a[i].get=read();a[i].left=read(); } for(ll i=1;i<=m2;++i) { b[i].get=read();b[i].left=read(); } prepare(); for(ll i=0;i<=n;++i) ans=max(ans,ansa[i]+ansb[n-i]); cout<<ans; } } } int main() { _xzy::My_main(); return 0; }