欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

D. Cutting Out (二分查找) Codeforces Round #521 (Div. 3)

程序员文章站 2022-06-04 19:41:43
...

原题链接: https://codeforces.com/contest/1077/problem/D

D. Cutting Out (二分查找) Codeforces Round #521 (Div. 3)
测试样例:

Examples
Input
7 3
1 2 3 2 4 3 1
Output
1 2 3 
Input
10 4
1 3 1 3 10 3 7 7 12 3
Output
7 3 1 3
Input
15 2
1 2 1 1 1 2 1 1 2 1 2 1 1 1 1
Output
1 1 

Note
The first example is described in the problem statement.
In the second example the only answer is [7,3,1,3] and any its permutations. It can be shown that you cannot choose any other array such that the maximum number of copies you can cut out would be equal to 2.
In the third example the array t can be cut out 5 times.

题意: 给你一个长度为nn的数组ss,要求你找到一个长为kk的数组tt,使得从ss中删去最多的tt

解题思路: 对于这个题目,我们会发现我们的删除次数会和数组ss中的tt数组中数字出现次数有关,我们要组成tt数组必然是选择出现次数最多的。那么也跟tt数组的长度有关,这个长度也同样影响着我们删除次数的值。那么不管别的,我们删除次数最少是11次,最大是nn次。对于我们的输入数据,我们所产生的的最大删除次数必然是在其中,所以我们也固然是要找到这个值,那么为了提高效率,这里我们采用二分法搜索,同样,对于每个值你必须设置checkcheck函数来检查该值是否有效,找到最大删除次数后自然可以遍历一遍数组输出我们能够删除的数字,知道长度达到kk。具体看代码。
AC代码:

/*
*邮箱:aaa@qq.com
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*/
#include<bits/stdc++.h>	//POJ不支持

#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair

using namespace std;

const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 2e5+4;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll>  pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//

int n,k,cnt[maxn];
//判断该删除次数是否可行
bool check(int mid,int k){
	int sum=0;
	rep(i,1,maxn-1){
		if(cnt[i]>=mid){
			sum+=cnt[i]/mid;
		}
		if(sum>=k)
			return true;
	}
	return false;
}
int main(){
	//freopen("in.txt", "r", stdin);//提交的时候要注释掉
	IOS;
	while(cin>>n>>k){
		int temp;
		memset(cnt,0,sizeof(cnt));//初始化
		rep(i,0,n-1){
			cin>>temp;
			cnt[temp]++;//统计出现次数。
		}
		int l=1,r=n,mid,result=0;
		//我们用二分法寻找最大删除次数。
		while(l<=r){
			mid=(l+r)>>1;
			if(check(mid,k)){
				result=mid;
				l=mid+1;
			}
			else{
				r=mid-1;
			}
		}
		//已经找到最大删除次数,开始输出即可。
		rep(i,1,maxn-1){
			if(cnt[i]>=result){
				temp=cnt[i]/result;
				while(temp--){
					cout<<i<<" ";
					k--;
					if(k==0){
						cout<<endl;
						break;
					}
				}
				if(k==0)
					break;
			}
		}
	}
	return 0;
}