TeMenHu P3242 呼和的数 题解

这题本来挺简单的,但是考场上没想出来

题意

构造一个数,使得是 \(i\) 的数位有 \(a_{i}\) 个且没有相邻的两个数位上的数字一样,多组数据。

分析

我们看到这道题,很容易想到贪心。对于从左到右依次考虑每个位,选和上一个位不同的数。这个思路很简单,但是会被这组数据卡掉:

输入:

0 1 2 0 0 0 0 0 0 0

输出:

212

它选了比较大的 \(2\) 来做第一位,用比较小的 \(1\) 来分隔两个 \(2\),如果使用我们的贪心思路,会输出 -1

我们再次分析问题后知道,其实每一个位不一定之选最小的,还可能选最多的,因为有时后要是不把最多的处理掉就没机会了。但是我们知道选最少的肯定优于选最多的,所以我们不到万不得已不会选最多的。

为了知道是不是万不得已,我们先假设剩下的数都排完了,那么我们可以用最多的隔一个就放一个,一共可以放 \(sum+1\) 个,其中 \(sum\) 表示剩下的数的数量(除去最多的数)。所以,我们是需要判断是否 \(maxn=sum+1\) 即可,其中 \(maxn\) 表示最多的数的数量。如果 \(maxn<sum+1\) 那么还可以等一等,\(maxn>sum+1\) 就没法补救了。

最后,我们还要判 \(-1\) 其实这和上面的很像,他只是判断一开始是不是就没法补救了。当 \(maxi \neq 0\) 时要判 \(maxn>sum+1\),否则要判 \(maxn>sum\),合起来就是 \(maxn>sum+(maxn \neq 0)\)

代码

#include <iostream>
using namespace std;

int T;
int a[10];

int main(){
    cin>>T;
    while(T--){
        int sum=0;
        int maxi=0;
        for(int i=0;i<10;i++){
            cin>>a[i];
            sum+=a[i];
            if(a[i]>a[maxi]){
                maxi=i;
            }
        }
        if(a[maxi]>sum-a[maxi]+(maxi!=0)){
            cout<<-1<<endl;
            continue;
        }
        int prev=0;
        do{
            int maxi=0;
            int mini=-1;
            for(int i=0;i<10;i++){
                if(a[i]>a[maxi]){
                    maxi=i;
                }
                if(i!=prev && a[i]>0 && mini==-1){
                    mini=i;
                }
            }
            if(a[maxi]==sum-a[maxi]+1){
                cout<<maxi;
                prev=maxi;
                a[maxi]--;
            }else{
                cout<<mini;
                prev=mini;
                a[mini]--;
            }
        }while(--sum);
        cout<<endl;
    }
    return 0;
}
posted @ 2025-03-06 22:21  xlaser  阅读(38)  评论(0)    收藏  举报