D. Martial Arts Tournament 题解(贪心)

题目链接

题目思路

这个题目感觉比较有意思

就是分为三段,让前面两段的数量尽可能接近\(2^i,2^j\)

这样的正确性感觉也不太会证明,不过看起来挺真的...

代码

#include<bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n;
int a[maxn];
int cnt[maxn];
int cal(int x,int y){
    int sum1=0,sum2=0,sum3=0;
    int i;
    for(i=1;i<=n;i++){
       if(sum1+cnt[i]>x){
            break;
       }
       sum1+=cnt[i];
    }
    for(;i<=n;i++){
        if(sum2+cnt[i]>y){
            break;
        }
        sum2+=cnt[i];
    }
    sum3=n-sum1-sum2;
    int z=1;
    while(z<sum3){
        z*=2;
    }
    return x-sum1+y-sum2+z-sum3;
}
signed main(){
    int _;scanf("%d",&_);
    while(_--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            cnt[a[i]]++;
        }
        int ans=inf;
        for(int i=0;i<=20;i++){
            for(int j=0;j<=20;j++){
                ans=min(ans,cal(1<<i,1<<j));
            }
        }
        for(int i=1;i<=n;i++){
            cnt[i]=0;
        }
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2022-01-17 11:29  hunxuewangzi  阅读(83)  评论(0编辑  收藏  举报