Codeforces 489C Given Length and Sum of Digits...
知识点:模拟、贪心、分支语句(、动态规划?)
题目
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;
}