我的思路
洛谷p4837
这道题很容易考虑到动态规划,但是它用动态规划无法完成。考虑二分答案,这样只需检验 mmm 分钟内是否可以把所有果树摘完。
将每个果树 iii 与坐标(WiW_iWi:果实数目, HiH_iHi:果树高度)对应,这样每个第一种类型的工人可以摘某一横坐标以左的果树,每个第二种类型的工人可以摘某一纵坐标以下的果树。
从右至左添加这些果树,一旦某一时刻某个第一种类型的工人可以摘当前果树,则它可以摘之后的所有果树。因此我们应尽量保留第一种类型的工人,即优先使用第二种类型的工人。
选择第二种类型的工人时,当然应该优先选择可以摘当前果树的第二种类型的工人中, YiY_iYi值最小的一个。
见代码:
#include<iostream>
#include<algorithm>
#include<string>
#include<functional>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int N=1000005;
const int AB=50005;
struct node{
int x,y;
node(int x=0,int y=0):x(x),y(y) { }
bool operator < (const node &B) const{
return x==B.x?y>B.y:x>B.x;
}
};
int n,numa,numb,ans;
node P[N];
int lx[AB],ly[AB];
int cntx[AB],cnty[AB];
int fat[AB];
inline void init(){
for(int i=1;i<=numb+1;i++)
fat[i]=i;
}
inline int Fat(int u){
return u==fat[u]?u:fat[u]=Fat(fat[u]);
}
inline bool check(int mid){
init();
int iter,pnt=numa;
for(int i=1;i<=numa;i++)
cntx[i]=0;
for(int i=1;i<=numb;i++)
cnty[i]=0;
for(int i=1;i<=n;i++){
iter=upper_bound(ly+1,ly+numb+1,P[i].y)-ly;
iter=Fat(iter);
if (iter!=numb+1){
cnty[iter]++;
if (cnty[iter]==mid) fat[iter]=iter+1;
}
else{
if (pnt==0 || P[i].x>=lx[pnt]) return 0;
cntx[pnt]++;
if (cntx[pnt]==mid) pnt--;
}
}
return 1;
}
inline int Bin(){
int L=0,R=n,MID;
while (L+1<R)
if (check(MID=(L+R)>>1))
R=MID;
else
L=MID;
return R;
}
int main(){
int maxx=0,maxy=0;
scanf("%d%d%d",&numa,&numb,&n);
for(int i=1;i<=numa;i++){
scanf("%d",&lx[i]);
maxx=max(maxx,lx[i]);
}
for(int i=1;i<=numb;i++){
scanf("%d",&ly[i]);
maxy=max(maxy,ly[i]);
}
sort(lx+1,lx+numa+1);
sort(ly+1,ly+numb+1);
for(int i=1;i<=n;i++){
scanf("%d",&P[i].x);
scanf("%d",&P[i].y);
if(P[i].x>=maxx && P[i].y>=maxy)
return printf("Impossible\n"),0;
}
sort(P+1,P+n+1);
ans=Bin();
printf("%d\n",ans);
return 0;
}