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;
}

浙公网安备 33010602011771号