题目描述:一家餐厅收到了n份订单,每份订单有开始和结束时间,餐厅可以选择接或不接,接受的订单时间必须互不重合,即任意一刻都不能被两个订单占用。问餐厅最多能接受几份订单。
啊这,乍看是经典DP,但是不能直接写,需要多思考。以订单结束顺序排序。
f[i]表示处理订单数为i时,所用的最小时间,发现f[i]有单调性。
每次对一个订单,用开始时间二分查找f[k]<lef<=f[k+1],更新f[k+1]=min(f[k+1],rig)
最后f[]数组最后不为INF的对应下标就是答案。
#include<bits/stdc++.h> //#define ll long long using namespace std; unordered_map<int,int> Mp; int n; struct Order { int lef,rig; }a[500010]; int b[1000010]; int f[1000010],cnt=1; bool my(Order a,Order b) { if(a.rig!=b.rig)return a.rig<b.rig; else return a.lef<b.lef; } void Reunion() { int k=0; sort(b+1,b+1+2*n); for(int i=1;i<=2*n;++i) { if(b[i]!=b[i-1]) Mp[b[i]]=++k; } sort(a+1,a+1+n,my); } int Find(int x) { int lef=0,rig=cnt,mid; //if(lef==rig) return 1; while(lef+1<rig) { mid=(lef+rig)>>1; if(f[mid]>x) rig=mid; else lef=mid; } if(x>f[rig]) return rig; else return lef; } int main() { cin>>n; for(int i=1;i<=n;++i) { cin>>a[i].lef>>a[i].rig; b[2*i-1]=a[i].lef,b[2*i]=a[i].rig; } Reunion(); int x,y,z; f[1]=Mp[a[1].rig]; for(int i=2;i<=n;++i) { x=Mp[a[i].lef]; y=Mp[a[i].rig]; //cout<<Find(x)<<endl; z=Find(x)+1; //cout<<z<<endl; //cout<<i<<' '<<x<<' '<<y<<endl; //Alt(y,z); if(!f[z]) f[z]=y; else f[z]=min(f[z],y); for(int j=cnt;;++j) { if(!f[j]) { cnt=j-1; break; } } //for(int i=1;i<=cnt;++i)cout<<f[i]<<' ';cout<<endl; //cout<<"gnerk"<<endl; } cout<<cnt<<endl; //system("pause"); return 0; }