Educational Codeforces Round 90 (Rated for Div. 2) - E. Sum of Digits

题意:

给定 n n n k   ( 1 ≤ n ≤ 150 , 0 ≤ k ≤ 9 ) k~(1 \leq n \leq 150,0 \leq k \leq 9) k (1n150,0k9) ,找到最小的 x x x ,使得:
f ( x ) + f ( x + 1 ) + ⋯ + f ( x + k ) = n f(x)+f(x+1)+ \cdots + f(x+k)=n f(x)+f(x+1)++f(x+k)=n
其中 f ( x ) f(x) f(x) 表示 x x x 的十进制数字的和

分析:

因为 0 ≤ k ≤ 9 0 \leq k \leq 9 0k9 ,所以最多会产生一次进位,

Ⅰ:

首先考虑没有进位的情况,那么容易想到枚举 x x x 个位数上的数,求出 x x x x + k x+k x+k 个位数的和 s u m sum sum,然后判断 i f ( ( n − s u m ) % ( k + 1 ) = = 0 ) if((n-sum)\%(k+1)==0) if((nsum)%(k+1)==0) 对应有没有解;

Ⅱ:

然后考虑有进位的情况,事先需要明确一点,因为是求最小值,所以除了个位数,是不会存在 9 + 1 9+1 9+1 进位的,因为产生一个 9 + 1 9+1 9+1 进位就等价于十进制数和减少了 8 8 8 ,得不尝试;所以个位数产生进位的情况下 十位数上最大为 8 8 8

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define frep(i,a,b) for(int i=a;i>=b;i--)
int n,k;
int sum[10][10];  //sum[i][j],表示 i~j 的和


void init()
{
	rep(i,0,9)rep(j,0,9){
		int a=0;
		if(i<=j) rep(z,i,j) a+=z;
		else{
			rep(z,i,9) a+=z;
			rep(z,1,j) a+=z;
		} 
		sum[i][j]=a;
	}
}

int main()
{
	//freopen("1.txt","r",stdin);
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	
	init();
	
	int t;
	cin>>t;
	while(t--)
	{
		vector<string>ANS;
	    cin>>n>>k;
	
	    rep(start,0,9)
	    {
	    	int end=(k+start)%10;
	    	
	    	int num=sum[start][end];
	    	if(num>n) continue;  //个位数的和就大于n,肯定无解
	    	if(num==n&&start<=end)  //最简单的解
	    	{
	    		string s;
	    		s+=(start+'0');
	    		ANS.pb(s);
	    		continue;
			}
			
			int m=n-num,cnt=0;
			if(start>end) cnt=end+1;
			// m 表示除开个位数的和
			// cnt 表示进位的数的个数
			
			if(cnt==0)  //没有产生进位
			{
				if(m%(k+1)!=0) continue;
				string s;
				s+=(start+'0');
				m/=(k+1);
				
				int tim=m/9;
				while(tim--) s+='9';
				if(m%9>0) s+=(m%9)+'0';  
				//从十位数位往上填,没有进位,肯定尽量填9,以此满足x最小的要求
				
				reverse(s.begin(),s.end());
				ANS.pb(s); 
			}
			
			else if(m>=cnt)  //有进位的情况,进位的数的十位数位都加1,所以得比较
			{
				if((m-cnt)%(k+1)==0)
				{
					int lft=m-cnt;
					lft/=(k+1);
					string s;
					s+=(start+'0');
					if(lft>0) //因为个位数有进位,十位数位上最多填8
					{
					    if(lft<=8) s+=(lft+'0'),lft=0;
					    else  s+='8',lft-=8;	
					}
					
					int tim=lft/9;
				    while(tim--) s+='9';
				    if(lft%9>0) s+=(lft%9)+'0';
				    
					reverse(s.begin(),s.end());
				    ANS.pb(s);
				}		
			}
		
		}
		if(ANS.size()==0) cout<<-1<<endl;
		else{
			int ML=1e9;
			for(string s:ANS) ML=min(ML,(int)s.length());  //先找到最小解的长度
			vector<string>Ne;
			for(string s:ANS) if(s.length()==ML) Ne.pb(s);
			sort(Ne.begin(),Ne.end()); 
			cout<<Ne[0]<<endl;
		}
	}
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值