New Year‘s Problem codeforce1619D

大致意思就是说,总共有m个商店,有n个朋友。每个商店里卖n中货物,每个商店的第i种货物能给第i个朋友带来不同的高兴值,且只能从n-1个商店里面选出n件礼物,使得n个朋友的高兴值尽量大一点,然后输出在这尽量大的高兴值队列中最小的高兴值是多少。Vlad wants to maximize the minimum of the joys of his friends.

首先,要明确,可能满足n个朋友的礼物的队列是不唯一的,也就是说,会有很多不同的值能够满足,要求得最优解,就必须要一次次逼近,所以,选用二分+贪心的算法。

选择二分理由:以所有给出的欢乐之为队列,求出最小值最大值,然后设置为l和r进行二分,当求得mid的时候,判断每个商店大于等于该值的欢乐值有多少个,当满足条件时即可更新答案。

选择贪心策略:由于对于每一个mid值的每个商店可能有不同的不同的i个数满足要求,所以按照个数从大到小能更好的找到满足n的个数。

需要注意的两点:1.极限测试样例是1e4 2.m*n≤2e5

初学二分注意:

1.必须找到一个单调的序列,这是能够二分最基本的要求。

2.必须找到往左走还是往右走的判定条件。

ac码:

#include<bits/stdc++.h>
using namespace std;

struct node
{
	int si;
	int cnt;
}ar[200100];

bool cmp(node a,node b)
{
	return a.cnt>b.cnt;
}

vector<int> vec[200100];
int book[200100],m,n;

bool judge(int val)
{
	int i,j,cnt,flag,lim;
	cnt=0;
	lim=0;
	for(i=0;i<m;i++)
	{
		ar[i].si=i;
		ar[i].cnt=0;
		for(j=0;j<n;j++)
		{
			book[j]=0;
			if(vec[i][j]>=val)
			{
				ar[i].cnt++;
			}
		}
	}
	sort(ar,ar+m,cmp);
	for(i=0;i<m;i++)
	{
		flag=0;
		for(j=0;j<n;j++)
		{
			if(vec[ar[i].si][j]>=val)
			{
				if(book[j]==0)
				{
					cnt++;
					book[j]=1;
					flag=1;
					if(cnt==n) break;
				}
			}
		}
		if(flag==1) 
		{
			lim++;
			if(lim>n-1 && cnt<n) return false;
			else if(cnt==n) break;
		}
	}
	if(cnt==n&& lim<=n-1) return true;
	else return false;
	
}

int main()
{
	int k;
	scanf("%d",&k);
	while(k--){
		int i,j,date;
		int minn=-1,maxx=0x3f3f3f3f,le,ri,mid,ans=-1;
		scanf("%d%d",&m,&n);
		for(i=0;i<m;i++)
		{
			vec[i].clear();
		}
		for(i=0;i<m;i++)
		{
			for(j=0;j<n;j++)
			{
				scanf("%d",&date);
				vec[i].push_back(date);
				minn=min(minn,date);
				maxx=max(maxx,date);
			}
		}
		le=minn;
		ri=maxx;
		while(le<=ri)
		{
			mid=(le+ri)/2;
			if(judge(mid))
			{
				ans=mid;
				le=mid+1;
			}
			else
			{
				ri=mid-1;
			}
		}
		printf("%d\n",ans);	
	}
	return 0;	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值