2018ccpc吉林 C:JUSTICE 思维

题意:n个物品,每个物品重量1/2^k[i],问可不可以分成两份,让这两份的总量都大于1/2

题解:因为两份都要大于1/2,那么我们两份都找出1/2,剩下的就无所谓了。我们把问题转化为,两份都需要找到一个1,因为 1/2==1/4+1/4,所以一个1等价于两个2,4个3.....,我们先从小到大排个序,令cnt1,cnt2表示这两组当前还需要pre这样的数的数量,如果cnt1+cnt2>后面剩余的数就直接break即可,cnt1和cnt2都为0时,即两组都已达到1/2,即符合条件

#include<bits/stdc++.h>
using namespace std;
int vis[100010];
struct node{
    int id;
    int x;
}a[100010];
int n;
int cmp(const node &xx,const node &yy)
{
    return xx.x<yy.x;
}
int main()
{
    int T;
    scanf("%d",&T);
    int nn=1;
    while(T--)
    {
        scanf("%d",&n);
         
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i].x);
            a[i].id=i;
            vis[i]=0;
        }
        printf("Case %d: ",nn++);
        sort(a+1,a+1+n,cmp);
        
        int flag=1;
        int pre=1;       //  pre初始为1,两组各需要一个即可 
        int cnt1=1,cnt2=1;
        for(int i=1;i<=n;i++)
        {
            while(cnt1+cnt2<=n-i+1&&pre<a[i].x)  //  转化为当前这个数,更新需要的数的数量 
            {
                cnt1=cnt1*2;
                cnt2=cnt2*2;
                pre++;
            }
            if(cnt1+cnt2>n-i+1) // 剩余的数的数量无法满足 
            {
                flag=0;
                break;
            }
            if(cnt1)
            {
                cnt1--;
                vis[a[i].id]=1;
            }
            else
            {
                cnt2--;
            }
            if(!cnt1 && !cnt2) break;  // 两个都满足了 
        }
        if(flag==0 || cnt1 || cnt2) puts("NO");
        else
        {
            puts("YES");
            for(int i=1;i<=n;i++)
            {
                printf("%d",vis[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/mmk27_word/article/details/89789770
今日推荐