【Luogu比赛-无聊出的小水题by darkf T1摘果实】一道好题

想了想,以后就不在题解标题里写出具体的算法了,想到有可能会有人看到标题后原本准备去做结果兴致全无,以后除非是模板题或特殊情况就最多吐吐槽了。 https://www.luogu.org/contestnew/show/8984 题目自己看,大致题意:给一堆果树,这些果树两个权值,一个个数,一个高度,我们有一些工人,他们都是只有一方面限制(例如可以摘的果树的个数不限制,高度限制多少一下),求最小花费时间,数据范围10万左右 看到第一个想法DP?然后想不出状态更写不出来。之后大概根据数据范围猜到应该是二分+贪心,怎么贪?贪不来又炸了。 考试中没做出来,,,难度 普及+ orz orz orz 果然太弱了额。 考后看标程和题解,才发现开始的大致思路是对的,只是实现上有点问题,堆?平衡树?单调队列?然后就懵圈了。然后在标程里突然注意到了并查集。仔细一看才发现这很强,直接代替了我想用的平衡树。 关于二分时间之后的验证实现方法:我们将A数组 sort,B数组 sort ,将所有果树 按照关键字 果实数量 sort 一下(果实数量多的在前面),然后开始枚举,由于考虑到如果一个对果实有限制的工人可以摘到当前果实了,那么他一定也能将剩下的果实摘到(后面果实数量更少),所以我们优先找对于高度有限制并且可以达到高度比较小的那个。由于这个有序,我们直接upper_bound一下,查询这个的并查集 (注意这个操作),如果这个摘的次数达到时间了,那么我们直接并查集连向比他大的那一个,这样每次我们upper_bound到的都是还没有用完次数并且可以满足条件的!如果在高度限制工人中找完了,就来果实限制中找,我们优先选可达到果实大的!如果这个大的都不满足,那么这些工人不满足了return 0,如果次数全用完了return 0,否则最后 return 1。 就这样一道 普及+题 就做完了。。。我真是太弱了。。。 蒟蒻的参考代码(也可以看答案标程)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
const int maxn = 200005;
int A,B,N;
struct node
{
	int w,h;
}z[maxn];
int a[maxn],b[maxn];
bool cmp(node aa,node bb)
{
	if(aa.w!=bb.w) return aa.w>bb.w;
	return aa.h>bb.h;
}
int cnta[maxn],cntb[maxn],bcj[maxn];
int gf(int x) { return bcj[x]==x?x:bcj[x]=gf(bcj[x]); } 
void init()
{
	for(int i=1;i<=A;i++) cnta[i]=0;
	for(int i=1;i<=B;i++) cntb[i]=0;
	for(int i=1;i<=B+1;i++) bcj[i]=i;
}
bool isok(int mid)
{
	init();
	int now = A;
	for(int i=1;i<=N;i++)//w big in the front()
	{
		int bbb = upper_bound(b+1,b+1+B,z[i].h)-b;
		bbb = gf(bbb);
		if(bbb!=B+1&&cntb[bbb]<mid)
		{
			cntb[bbb]++;
			if(cntb[bbb]==mid) bcj[bbb]=bbb+1;
		}
		else
		{
			if(!now||z[i].w>=a[now]) return 0;
			cnta[now]++;
			if(cnta[now]==mid) now--;
		}
	}
	return 1;
}
int main()
{
	scanf("%d%d%d",&A,&B,&N);
		int maxa = 0; int maxb = 0;
	for(int i=1;i<=A;i++) 
	{
		scanf("%d",&a[i]);
		maxa = max(maxa,a[i]);
	}
	for(int i=1;i<=B;i++)
	{
		scanf("%d",&b[i]);
		maxb = max(maxb,b[i]);
	}
	for(int i=1;i<=N;i++)
	{
		scanf("%d%d",&z[i].w,&z[i].h);
		if(z[i].w>=maxa&&z[i].h>=maxb)
		{
			puts("Impossible");
			return 0;
		}
	}
	sort(a+1,a+1+A); sort(b+1,b+1+B);
	sort(z+1,z+1+N,cmp);
	int L = 1; int R = N; int ans;
	while(L<=R)
	{
		int mid = (L+R)>>1;
		if(isok(mid)) ans=mid,R=mid-1;
		else L=mid+1;
	}
	printf("%d",ans);
}
 
posted @ 2018-07-31 22:42  Newuser233  阅读(4)  评论(0)    收藏  举报