1. 程式人生 > >D. Cutting Out

D. Cutting Out

---恢復內容開始---

連結

[https://codeforces.com/contest/1077/problem/D]

題意

給你n,k,n個數,找出長度為k,的子串(不需連續),使得該子串數量最多

分析

1.肯定統計每個數字的數量
2.看那些數字數量大於0,儲存數量和該數數值
3.對儲存的根據數量從小到大排序
4.reverse就變成從大到小排序
5.選出前數量前k大的前k個數,
6.二分貪心查詢
很經典的二分吧

程式碼

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
const int N=2e5+10;
int f[N];
int main(){
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); 
    int n,k,x,i,j,ma; 
    ma=0;
    //freopen("in.txt","r",stdin);
    cin>>n>>k;
    for(i=0;i<n;i++){
        cin>>x; f[x]++; ma=max(ma,x);
    }
    vector<pair<int,int> > v1,v2;
    for(i=1;i<=ma;i++) if(f[i]) v1.pb(mp(f[i],i));
    sort(v1.begin(),v1.end());
    reverse(v1.begin(),v1.end());
    j=0;
    for(i=0;i<v1.size();i++)
    {
        j++; if(j>k) break;
        v2.pb(mp(v1[i].fi,v1[i].se));
    }
    
    vector<int> ans;
    int l=1,r=N;
    while(l<=r){
        int mid=(l+r)>>1;
        int sum=0;
        vector<int> tem;
        for(i=0;i<v2.size();i++)
        tem.pb(v2[i].fi/mid),sum+=tem[i];
        if(sum>=k){
            ans.clear();
            int cnt=0;
            for(i=0;i<v2.size();i++){
                int t=tem[i];
                while(cnt<k&&t--)
                ans.pb(v2[i].se),cnt++;
            }
            l=mid+1;
        }
        else r=mid-1;
    }
    for(i=0;i<ans.size();i++)
    cout<<ans[i]<<' ';
    cout<<endl;
    return 0;
}