2022-06-03每日刷题打卡

本文介绍了一道关于整数排列的编程题,HoshiYo是一个魔术师,他尝试通过重新排列数字来得到特定条件的整数。题目要求找到满足所有数字被使用、首位不为0(除非数本身就是0)、相邻数字不相同的最小整数。文章通过分析四种可能情况,给出了相应的解题策略,并提供了C++代码实现。
摘要由CSDN通过智能技术生成

2022-06-03每日刷题打卡

代码源——每日一题

一个小整数 - 题目 - Daimayuan Online Judge

HoshiYo是一个魔术师。他擅长使用魔术,但他不擅长数学。在魔法学校的数学课上,HoshiYo学习了整数的知识。他突然发现一个有趣的事情:用他强大的魔法,他可以通过重新排列数字来改变一个整数。

从形式上看,从0∼9的每个数字,第i个数字是ai,说明有ai个这样的数。HoshiYo想得到一个符合以下规则的整数。

所有给定的数字都被使用。

第一个数不能是0,除非这个数就是0。

相邻的数字不能相同。

HoshiYo想知道他能用这些数字得到的最小整数是多少。

输入

给出10个整数a0,a1,…,a9(0≤ai≤105),表示不同数字的数量。可以保证1≤所有数总和≤105。

输出

输出HoshiYo能在一行中得到的最小整数。如果没有解决方案,就用一行字输出-1。

样例输入
2 0 1 0 0 1 0 2 0 0
样例输出
205707

问题解析

这题其实挺好想的,如果没写出来可能是想复杂了。

我们先分析一下,这里无非就四种情况:

1、数量最多的那个数,数量是其它数的总和还多1以上

2、数量最多的那个数,数量是其它数的总和还多1

3、数量最多的那个数,数量正好等于其它数的总和

4、数量最多的那个数,数量小于其它数的总和

(以下最多数量的数我们简称x,其它数量的数简称y)

如果是第一种情况,那么显然无论我们怎么样,必然会有相邻的数相同的情况出现,直接输出-1。

如果是第二种情况,那么第一个数只能是x,然后一个y,一个x这样交替放,并且末尾也会是这个最多数,即:xyxy……xyx。

如果是第三种情况,那么第一个数可以是x也可以是y,即:xyxy……xy或yxyx……yx这样子。

如果是第四种情况,我们可以随便摆,只要保证相邻数不相同即可。

情况分析完毕,我们开始想题:

我们每次先遍历一遍这十个数,计算一下数量最多的数和其它数量数总和的关系,然后我们根据关系来取数:

如果是第一种情况,我们直接输出-1结束程序即可;如果是第二种情况,我们第一个数只能是这个最多数量的数;如果是第三、四种情况,我们可以取这十个数中最小的那个数(不强迫选,那为了数最小,我们肯定要选小的数放在前面),但要注意不能和上一个数相同。而且对于第2、3、4种情况,如果这是我们取的第一个数,那么这个数不能是0,因为除了0本身我们不能有前导0(建议一开始特判一下只有一个0,其它数都没有的情况),如果我们必须要取0了,那也是输出-1。

取完一个数后,我们把那个数的个数-1,然后回到开头进行下一步。

数的总个数是2e4,我们每次取一个数要遍历一下这十个数,然后就可以根据情况判断了,总复杂度也才1e5。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50;
ll n, v[10];

bool dfs(vector<int>& res)
{
    int sum = 0, mx = 0, ans = -1;
    for (int i = 0; i < 10; i++)
    {
        sum += v[i];
        if (v[i] > mx)
        {
            mx = v[i];
            ans = i;
        }
    }
    if (sum == 0)return true;
    sum -= mx;
    
    if (sum + 1 == mx)
    {
        if (ans == 0 && res.empty())
        {
            return false;
        }
        else
        {
            res.push_back(ans);
            v[ans]--;
        }
    }
    else if (sum + 1 < mx)
    {
        return false;
    }
    else
    {
        int u = res.size() == 0 ? 1 : 0;
        int k = u == 1 ? -1 : res.back();
        for (int i = u; i < 10; i++)
        {
            if (v[i] != 0 && i != k)
            {
                res.push_back(i);
                v[i]--;
                break;
            }
        }
    }
    return dfs(res);
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int sum = 0;
    for (int i = 0; i < 10; i++)
    	cin >> v[i], sum += v[i];
    if (v[0] == 1 && sum == 1)
    {
        cout << 0 << endl;
        return 0;
    }
    vector<int>res;
    if (dfs(res))
    {
        if (res.empty())cout << -1;
        else for (auto i : res)cout << i;
            cout << endl;
    }
    else
    {
    	cout << -1 << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值