洛谷P4835 摘果实
题面:https://www.luogu.com.cn/problem/P4835
题解:我们先将规划性问题转化为判定性问题:二分答案。
现在的问题是:如何check?
设当前二分的答案为\(T\),也就是说每个工人最多采摘\(T\)次。
考虑如何规划才能采完所有果子。
对于对数目\(w\)有限制的工人,若将他们按\(a[i]\)(限定数目)
排序,可以发现:\(a[i]\)越小,能摘的东西就越少。废话
而我们又想“人尽其用”,于是我们发现一种可行的贪心策略:
对于\(a[i]\)小的工人,让他们在能力范围内尽量摘\(h[i]\)大的
果子。
想想这么做为什么是正确的:对于\(h[i]\)越大的果子,能摘它的
b类工人越少,因此a类工人摘这些果子总是最优的。
整个过程可以用一个大根堆来实现。
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
template<class D>I read(D &res){
res=0;register D g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
typedef pair<int,int>pii;
struct P{
int h,w,id;
}p[101000];
priority_queue<pii>q;
pii nd;
int n,m,A,B,a[50500],f[50500],b[50500],g[50500],vis[101000];
inline bool bb2(P x,P y){return x.h^y.h?x.h<y.h:x.w<y.w;}
inline bool bb1(P x,P y){return x.w^y.w?x.w<y.w:x.h<y.h;}
IN ck(int x){
memset(vis,0,sizeof(vis));
while(!q.empty())q.pop();m=0;
F(i,1,A){
while(m<n&&p[m+1].w<a[i])m++,q.emplace(make_pair(p[m].h,m));
for(re j=1;j<=x&&!q.empty();j++){
nd=q.top();q.pop();
vis[nd.second]=1;
}
}
F(i,m+1,n)q.emplace(make_pair(p[i].h,i));
if(q.empty())return 1;
FOR(i,B,1){
for(re j=1;j<=x&&!q.empty();j++){
nd=q.top();q.pop();
if(b[i]<=nd.first)return 0;
}
if(q.empty())return 1;
}
if(q.empty())return 1;
return 0;
}
IN divided(int x,int y){
//cout<<x<<" "<<y<<endl;
if(x==y)return x;
re mid=(x+y)>>1;
if(ck(mid))y=mid;
else x=mid+1;
return divided(x,y);
}
int main(){
read(A);read(B);read(n);
F(i,1,A)read(a[i]);sort(a+1,a+1+A);
F(i,1,B)read(b[i]);sort(b+1,b+1+B);
F(i,1,n)read(p[i].w),read(p[i].h);
sort(p+1,p+1+n,bb1);
FOR(i,n,1){
if(a[A]<=p[i].w&&b[B]<=p[i].h){
cout<<"Impossible";
return 0;
}
}
m=A+B;
if(n%m==0)m=n/m;
else m=(n/m)+1;
//system("pause");
printf("%d",divided(m,n));
return 0;
}