codeforces1077D. Cutting Out(优先队列)

D. Cutting Out

time limit per test

3 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

You are given an array ss consisting of nn integers.

You have to find any array tt of length kk such that you can cut out maximum number of copies of array tt from array ss.

Cutting out the copy of tt means that for each element titi of array tt you have to find titi in ss and remove it from ss. If for some titi you cannot find such element in ss, then you cannot cut out one more copy of tt. The both arrays can contain duplicate elements.

For example, if s=[1,2,3,2,4,3,1]s=[1,2,3,2,4,3,1] and k=3k=3 then one of the possible answers is t=[1,2,3]t=[1,2,3]. This array tt can be cut out 22 times.

  • To cut out the first copy of tt you can use the elements [1,2––,3,2,4,3––,1––][1,2_,3,2,4,3_,1_] (use the highlighted elements). After cutting out the first copy of tt the array ss can look like [1,3,2,4][1,3,2,4].
  • To cut out the second copy of tt you can use the elements [1––,3––,2––,4][1_,3_,2_,4]. After cutting out the second copy of tt the array ss will be [4][4].

Your task is to find such array tt that you can cut out the copy of tt from ss maximum number of times. If there are multiple answers, you may choose any of them.

Input

The first line of the input contains two integers nn and kk (1≤k≤n≤2⋅1051≤k≤n≤2⋅105) — the number of elements in ss and the desired number of elements in tt, respectively.

The second line of the input contains exactly nn integers s1,s2,…,sns1,s2,…,sn (1≤si≤2⋅1051≤si≤2⋅105).

Output

Print kk integers — the elements of array tt such that you can cut out maximum possible number of copies of this array from ss. If there are multiple answers, print any of them. The required array tt can contain duplicate elements. All the elements of tt (t1,t2,…,tkt1,t2,…,tk) should satisfy the following condition: 1≤ti≤2⋅1051≤ti≤2⋅105.

Examples

input

Copy

7 3
1 2 3 2 4 3 1

output

Copy

1 2 3 

input

Copy

10 4
1 3 1 3 10 3 7 7 12 3

output

Copy

7 3 1 3

input

Copy

15 2
1 2 1 1 1 2 1 1 2 1 2 1 1 1 1

output

Copy

1 1 

Note

The first example is described in the problem statement.

In the second example the only answer is [7,3,1,3][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 22.

In the third example the array tt can be cut out 55 times.

 

一、原题地址

点我传送

 

二、大致题意

给一串长度为n的序列,每次会从序列中删去一个选定的序列 T ,T的长度等于 k 。询问选定的 T 是什么可以使得删除的操作数尽可能多。

 

三、大致思路

首先统计每个数字在原序列中出现的次数。为了处理一个数字在序列T中可以存在多个,实际上它能被取的次数,就是在原序列中总数num除以被选择了几次ci。所以用一个优先队列记录 num/ci ,每次的队首元素就一定是最优解了。

 

四、代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
using namespace std;

typedef long long LL;



struct Node
{
    int val,num;
    int ci;
    bool operator < (const Node b)const
    {
        return num/ci<b.num/b.ci;
    }
}arr[200005];
int sum[200005];
int n,k;
int main()
{
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        sum[x]++;
    }
    int cnt=0;
    priority_queue<Node>q;
    for(int i=1;i<=200000;i++)
    {
        if(sum[i]!=0)
        {
            cnt++;
            arr[cnt].num=sum[i];
            arr[cnt].val=i;
            arr[cnt].ci=1;
            q.push(arr[cnt]);
        }
    }
    vector<int>ans;
    while(ans.size()<k)
    {
        Node t=q.top();
        q.pop();
        ans.push_back(t.val);
        t.ci++;
        q.push(t);
    }
    for(int i=0;i<ans.size();i++)
        printf("%d ",ans[i]);
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值