Codeforces 489C Given Length and Sum of Digits...

"本文介绍了如何解决一道编程题目,要求找到具有特定位数和数字之和的最小和最大非负整数。通过分析最大值和最小值的特性,可以采用贪心策略来优化解决方案,避免暴力搜索。代码实现中展示了两种不同的思路,一种是直接贪心,另一种是动态规划。在某些情况下,可能存在无解的情况,此时输出"-1-1"。"
摘要由CSDN通过智能技术生成

知识点:模拟、贪心、分支语句(、动态规划?)

题目

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.

输入

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.

输出

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).

样例

输入1

2 15

输出1

69 96

输入2

3 0

输出2

-1 -1

题意

求指定位数的最小和最大的各位数之和等于指定数字的两个数字。

思路

在vjudge上做过一次,当时模拟写爆了,第二次在cf上看到了,wa了一发就成功了。cf的tag上还标注了dp,读者可以试试能否用动态规划。
最暴力的方法是dfs对每一位枚举9次,复杂度为O(9^m)。
由于题目要求求最大和最小的数字,所以分析最大和最小的数字的判断方法。由于位数由题目给定,一个数字大于另一个数字的判断方法为:对这个数字的数位从左往右遍历,如果当前数位上的数字小于另一个数字当前数位上的数字,则这个数小于另一个数,否则如果大于则这个数大于另一个数,否则(即相等情况)对两个数字的右一位进行如上判断,直到数位没有右一位时,两个数字相等。
进一步分析可发现对一个已经符合题意的数字,对任意一位上的数字减去不大于该位上的数字的数,再对任意一位上的数字加上减去的数,使得加完后的数不超过9,相当于移动数字1,整个数字的数位和不变,即状态不发生改变,所以可以采取贪心策略。
对最小数而言,因为题意说明不含前导0,所以首位必不为0,可以贪心地增加1,如果数位和连1都没有,就无法得到答案。剩下的数移到最右边,使得对两个数按数位从左往右比较大小的时候尽可能提前判断出当前数位比另一个数位小。由于数位不能超过9,所以如果剩下的数超过9,就对末位增加9,如果仍然超过9,就对次末位增加9,循环直到剩下的数不超过9,就对当前位增加9。如果当前位增加9后大于9了,说明无论怎么填都有剩余,无法得到答案。
对最大数而言,数移到最左边,使得对两个数按数位从左往右比较大小的时候尽可能提前判断出当前数位比另一个数位大,填数方法同理。
实现思路见代码。代码1为第二次在cf上写的,代码2为第一次在vjudge上写的,代码2特判很少,对特殊数据有普适性。

代码1

#include"bits/stdc++.h"
#define ll long long
using namespace std;
const int N=1e2+10;

ll m,s;
ll ans[N];

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  cin>>m>>s;
  ll t=s;

  if(m==1&&s==0) goto y;
  ans[1]=1;
  --t;
  if(t<0) goto x;
  for(ll i=m; i>=2; --i) {
    if(t-9<0) {
      ans[i]=t;
      t=0;
      break;
    } else {
      ans[i]=9;
      t-=9;
    }
  }
  if(t+ans[1]>9) goto x;
  ans[1]+=t;

  for(ll i=1; i<=m; ++i) {
    cout<<ans[i];
  }
  cout<<' ';

  memset(ans,0,sizeof ans);
  t=s;
  if(t==0) goto x;
  for(ll i=1; i<=m; ++i) {
    if(t-9<0) {
      ans[i]=t;
      t=0;
      break;
    } else {
      ans[i]=9;
      t-=9;
    }
  }

  for(ll i=1; i<=m; ++i) {
    cout<<ans[i];
  }
  cout<<endl;
  return 0;
y:
  cout<<"0 0"<<endl;
  return 0;
x:
  cout<<"-1 -1"<<endl;
  return 0;
}

代码2

//克服WA难,终得AC
#include"bits/stdc++.h"
#define ll long long
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define reb(i,a,b) for(ll i=a;i<=b;i++)
#define rev(i,a,b) for(ll i=a-1;i>=b;i--)
#define red(i,a,b) for(ll i=a;i>=b;i--)
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;

ll m,s;
ll digit[110];

int main() {
  scanf("%lld%lld",&m,&s);
  ll t=s;
  rev(i,m,0) {
    if(t>10) {
      digit[i]=9;
      t-=9;
    } else if(t>1) {
      digit[i]=t-1;
      t=1;
    } else
      digit[i]=0;
  }
  if(t&&digit[0]<9) {
    digit[0]+=t;
    t=0;
  }
  if(t||digit[0]==0&&m!=1) goto x;
  rep(i,0,m)
  cout<<digit[i];
  cout<<" ";
  t=s;
  rep(i,0,m) {
    if(t>9) {
      digit[i]=9;
      t-=9;
    } else if(t>0) {
      digit[i]=t;
      t=0;
    } else digit[i]=0;
  }
  rep(i,0,m) cout<<digit[i];
  cout<<endl;
  return 0;
x:
  cout<<"-1 -1"<<endl;
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值