Educational Codeforces Round 90 (Rated for Div. 2) 参与排名人数12840
[codeforces 1373E] Sum of Digits 十位数百位数乃至更高位的进位不可能发生
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址http://codeforces.com/contest/1373/problem/E
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
E - Sum of Digits | GNU C++17 | Accepted | 31 ms | 3900 KB |
题目大意:寻找满足公式的最小x.若找不到,输出-1.
难点:思考了一下,主要涉及进位比较难处理。又想了想,满足条件的x应该有时会比较多,如何找最小?
基本思路:
1.十位数百位数乃至更高位的进位不可能发生,举例如下
x=99,k=3
x+0=99
x+1=100
x+2=101
x+3=102
各位位上数字之和9+9+1+0+0+1+0+1+1+0+2=24,对应的n是24
n=24可以找到比上述x更小的情况
x=18,k=3
x+0=18
x+1=19
x+2=20
x+3=21
各位位上数字之和1+8+1+9+2+0+2+1=24
2.因要找最小的x,可以大致判定x+0,x+1,x+2,......,x+k,这k+1个数,在各个位置上的数字差异很小。
3.因要找最小的x,低位尽可能摆大的数,高位尽可能的摆小的数,考虑到要凑成n,故个位上的数需要枚举(从0枚举到9)。
样例模拟过程如下,以下模拟过程,若阅读有障碍,可结合AC代码进行学习。
42 7
4
x的个位是0
0,0+1=1,0+2=2,0+3=3,0+4=4,0+5=5,0+6=6,0+7=7
个位上数字之和0+1+2+3+4+5+6+7=28
还剩42-28=14
14无法均分为7+1=8份,此种情况排除
x的个位是1
1,1+1=2,1+2=3,1+3=4,1+4=5,1+5=6,1+6=7,1+7=8
个位上数字之和1+2+3+4+5+6+7+8=36
还剩42-36=6
6无法均分为7+1=8份,此种情况排除
x的个位是2
2,2+1=3,2+2=4,2+3=5,2+4=6,2+5=7,2+6=8,2+7=9
个位上数字之和2+3+4+5+6+7+8+9=44
还剩42-44=-2
还剩下-2,此种情况排除
x的个位是3
3,3+1=4,3+2=5,3+3=6,3+4=7,3+5=8,3+6=9,3+7=10(1+0=1)
个位上数字之和3+4+5+6+7+8+9+1=43
还剩42-43=-1
还剩下-1,此种情况排除
x的个位是4
4,4+1=5,4+2=6,4+3=7,4+4=8,4+5=9,4+6=10(1+0=1),4+7=11(1+1=2)
个位上数字之和4+5+6+7+8+9+1+2=42
还剩42-42=0
还剩下0,此种情况,十位上数字均分的是0/(1+7)=0
因涉及个位上的进位,x+k对应的十位数是0+1=1
接下来处理x+k
1*10+2=12,12-1=11(注,-1是扣除4+7=11(1+1=2)对应的1+1=2的十位上的1的影响),此处若不明,可结合AC代码进行研究。
11-7=4此时,算出的即是x=4.
AC代码如下:
#include <cstdio>
#include <algorithm>
#define LL long long
#define INF (LL)1<<63-1
using namespace std;
int p[]={0,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9};//0,1,2,3,4,5,6,7,8,9,10(1+0=1),11(1+1=2),12(1+2=3),13(1+3=4),14(1+4=5),15(1+5=6),16(1+6=7),17(1+7=8),18(1+8=9)
LL ans;
LL solve(int st,int n,int k){
int i,sum=0;
LL ret=0,pow=10;//注意pow=10,从十位开始
for(i=st;i<=st+k;i++)sum+=p[i];//个位之和,已包含进位,这个技巧妙啊
n-=sum;//剩下的和值
if(n<0||n%(k+1))return INF;//n<0表示凑不成n;n%(k+1)!=0表示剩下的数据,无法均分
n/=(k+1);//平均分为k+1份,每份的数值
if(st+k>=10)n++;//研究最大的数x+k.n++记录的是十位的进位
while(n>0){
int tmp=9;//除个位,最高位外的数据
if(n<9)tmp=n;//可能的最高位数据
ret+=tmp*pow;
pow*=10;
n-=9;//低位,数据越大越好
}
ret+=p[st+k];//补回个位,对应x+k数据
if(st+k>=10)ret--;//退位,尾巴多了1,故退去
if(ret>=k)return ret-k;
else return INF;
}
int main(){
int t,i,n,k;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
ans=INF;
for(i=0;i<=9;i++)//个位上的数值
ans=min(ans,solve(i,n,k));//,printf("i=%d ans=%lld\n",i,ans);
if(ans==INF)printf("-1\n");
else printf("%lld\n",ans);
}
return 0;
}