CodeForces489C. Given Length and Sum of Digits 【dp 贪心】

本文介绍了一种算法,用于找出特定长度和数字之和条件下最大的数和最小的数,并提供了两种实现方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
You have a positive integer m and a non-negative integer s. Your task is to find the smallest and the largest of the numbers that have length m and sum of digits s. The required numbers should be non-negative integers written in the decimal base without leading zeroes.

Input
The single line of the input contains a pair of integers m, s (1 ≤ m ≤ 100, 0 ≤ s ≤ 900) — the length and the sum of the digits of the required numbers.

Output
In the output print the pair of the required non-negative integer numbers — first the minimum possible number, then — the maximum possible number. If no numbers satisfying conditions required exist, print the pair of numbers “-1 -1” (without the quotes).

Examples
inputCopy
2 15
output
69 96
inputCopy
3 0
output
-1 -1

两种处理思路:
1.最大值和最小值分别处理。最大值就是正着放置,尽可能填9。最小值需要注意开头不能为0,所以先设置第一位为1,同时总和减一,保证之后的更新不会出现第一位为0的情况。
2**第二种方法很巧妙。**最大值和最小值之间是有关系的。如果取得最大值,最末尾不为0,那么倒置即为最小值。开始不考虑首位,按贪心同第一种方法求,尽可能填9.为了避免直接倒置输出倒置最小值首位为0.
利用 for(int k = 0;!num[k];k++); 注意分号。这条语句是为了找到从左到右第一个不为0的数的位置(最高非零位)。然后 num[0]++; num[k]–; 如果第一位为0 那么让它加一满足条件,同时让最高非零位减一,保证总和为s。如果首位本身不为0,那么跳出循环时k==0.
那么之后进行num[0]++; num[k]–; 相当于每一位都没有变化。

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int num[105];
int  main()
{
    int m,s;
    cin>>m>>s;
    num[0] = 1;
    int sum = s-1;
    //找到最小值 倒着放置 低位尽可能大 
    if(s==0&&m ==1) 
    {
        cout<<0<<' '<<0<<endl;
    }
    else if(m*9<s||s<1)//s<1成立的情况只有上面m==1时 否则都是错误的
    {
        cout<<-1<<' '<<-1<<endl; 
    } 
    else
    {
        for(int i = m-1;i>=0;i--)
        {
            if(9-num[i]<sum)
            {
                sum -=9-num[i];
                num[i] = 9;
            }
            else//该位已经不足够置成9 就把剩余的sum放入 
            {
                num[i] +=sum;
                break;
            }

        }
        for(int i = 0;i<m;i++)
        {
            cout<<num[i];
        } 
        cout<<' ';
        //最大值 正向放置 高位尽可能大 
        memset(num,0,sizeof(num));
        sum = s;
        for(int i = 0;i<m;i++)
        {
            if(9-num[i]<sum)
            {
                sum -= 9-num[i];
                num[i] = 9;
            } 
            else
            {
                num[i] += sum;
                break;
            }
        } 
        for(int i = 0;i<m;i++)
        {
            cout<<num[i];
        }
        cout<<endl;
    }

    return 0;
}

第二种方法

#include<iostream>
#include<cstdio>
using namespace std;
int num[105];
int main()
{
    int m,s;
    while(scanf("%d%d",&m,&s)!=EOF)
    {
        if(m==1&&s==0)
        {
            cout<<0<<' '<<0<<endl;
            continue;
        }
        else if(m*9<s||s<1)
        {
            cout<<-1<<' '<<-1<<endl;
            continue;
        }
        for(int i = m-1;i>=0;i--)
        {
            num[i] = min(s,9);
            s -= min(s,9);
        }
        int k;
        for(k = 0;!num[k];k++);//这一步是要找到从左到右第一个不为0的位置 
        num[0]++; 
        num[k]--;//如果第一位就不是0,那么k=0又将第一位恢复不影响
        for(int i = 0;i<m;i++)
        {
            cout<<num[i];
        } 
        cout<<' ';
        num[0]--;
        num[k]++;
        for(int i = m-1;i>=0;i--)
        {
            cout<<num[i];
        }
        cout<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值