Justice HDU-6657 贪心

Put simply, the Justice card represents justice, fairness, truth and the law. You are being called to account for your actions and will be judged accordingly. If you have acted in a way that is in alignment with your Higher Self and for the greater good of others, you have nothing to worry about. However, if you have
acted in a way that is out of alignment, you will be called out and required to own up to your actions. If this has you shaking in your boots, know that the Justice card isn’t as black and white as you may think.

On the table there are n weights. On the body of the i-th weight carved a positive integer ki , indicating that its weight is 12ki gram. Is it possible to divide the n weights into two groups and make sure that the sum of the weights in each group is greater or equal to 12 gram? That’s on your call. And please tell us how if possible.
Input
In the first line of the input there is a positive integer T (1 ≤ T ≤ 2000), indicating there are T testcases.
In the first line of each of the T testcases, there is a positive integer n (1 ≤ n ≤ 105, ∑n ≤ 7 × 105), indicating there are n weights on the table.
In the next line, there are n integers ki (1 ≤ ki ≤ 109), indicating the number carved on each weight.
Output
For each testcase, first print Case i: ANSWER in one line, i indicating the case number starting from 1 and ANSWER should be either YES or NO, indicating whether or not it is possible to divide the weights. Pay attention to the space between : and ANSWER.
If it’s possible, you should continue to output the dividing solution by print a 0/1 string of length n in the next line. The i-th character in the string indicating whether you choose to put the i-th weight in group 0 or group 1.
Sample Input
3
3
2 2 2
3
2 2 1
2
1 1
Sample Output
Case 1: NO
Case 2: YES
001
Case 3: YES
10

题意:
题目其实就是给我们一组数 给出的数可以看做2的N次幂 作为一个分子为1的分数的分母 问所有的数是否能凑出两个大于等于二分之一的数 并打印出解决方案

方案:
拿到题目不难看出只要我们的所有数能凑出两个1就是 YES ,反之为 NO,但是如何判断与如何打印路径成了问题 我的解决方案是先用一个tree_map记录每一个数的多少 保证有序 再用hash_map记录每个数的多少 对tree_map从大先小遍历 大于等于2则上位加上本位除于2的数 最后判断1的个数即,接下来是打印可行的方法,其实我们只需要把一组数中能拼成1的数标记即可 这样一组必为二分之一,如何标记呢,我们可以这样去想 需要一个1,就是需要两个2,需要两个2就是需要四个4,以此类推 我们可以先做一个预处理 判断出每个数字的多少 再遍历一遍数组即可

AC代码

#include<iostream>
#include<algorithm>
#include<map>
#include<cstring>
#include<unordered_map>
using namespace std;
map<int,int>mp;
unordered_map<int,int>tmp;
int q;
int m;
int book[100000+10];
int flag[100000+10];
int ans;
int main()
{
    scanf("%d",&q);
    while(q--)
    {
        tmp.clear();
        mp.clear();
        memset(book,0,sizeof(book));
        memset(flag,0,sizeof(flag));
        unordered_map<int,int>cep;
        scanf("%d",&m);
        for(int i=0;i<m;i++)
        {
            scanf("%d",&book[i]);
            mp[book[i]]++;
            tmp[book[i]]++;
        }
        for(auto x=mp.rbegin();x!=mp.rend();x++)
        {

            if(x->first==1)
            continue;
            if(x->second>=2)
            {
                mp[x->first-1]+=(x->second/2);
                x->second%=2;
            }
        }
        if(mp[1]>=2)
        printf("Case %d: YES\n",++ans);
        else{
            printf("Case %d: NO\n",++ans);
            continue;
        }
        int tt=2; //因为存在1的话直接比标记一个就好
        if(!tmp[1])
        {
            cep[2]=2;
            while(1)
            {
                if(tmp.find(tt)!=tmp.end())
                {
                    if(cep[tt]-tmp[tt]<=0)
                    {
                        break;
                    }else{
                        cep[tt]-=tmp[tt];
                        cep[tt+1]=cep[tt]*2; //所需的下一个
                        cep[tt]=tmp[tt];//这种数字需要的个数
                        tt++;
                    }
                }else{
                    cep[tt+1]=cep[tt]*2;
                    cep[tt]=0;
                    tt++;
                }
            }
        }   
        else 
        cep[1]=1;
        int number=mp.size();
        for(int i=0;i<m;i++)
        {
            if(!number)
            break;
            else if(cep[book[i]]){
                flag[i]=1;
                cep[book[i]]--;
                if(!cep[book[i]])
                number--;
            }
        }
        for(int i=0;i<m;i++){
            printf("%d",flag[i]);
        }
        putchar('\n');
    }
    return 0;
}

不得不说这个重现赛打的是有点自闭的 B题前后重构了了两次 贡献了六百多行代码也没出来 后面的题都没有看也没时间敲 C E F下去都是很快A掉了 I题三人一起也没什么问题 还是要有策略 大模拟最多一个小时 下次加油了

ps:我讨厌大模拟

posted @ 2022-07-02 13:18  李兆龙的博客  阅读(12)  评论(0编辑  收藏  举报