CF1373E Sum of Digits

Many problem solutions on the Internet are not understood, and some of the "obvious" conclusions in the solutions are completely unobvious...

If we enumerate the ones digit of the first number of this sequence, then if this sequence exists, it must be constructed. (Because k<=9, the length of the sequence is <=10, and it will only be carried once at most)
1. When there is no carry in this sequence and the last digit of the first number is now, it can be expressed as: a+now, a+now+1, a+now+2,… ,a+now +k. (Among them, because there is no carry, so now+k<=9, and a means that they have the same highest order to the tenth place)
In this case, after knowing now, k and n, it can be obtained.
	if (now+k<=9)
		{
    
    
			int last=n-(now*(k+1)+(1+k)*k/2);
			if (last<0 || last%(k+1)!=0) continue;
			last/=(k+1);
			int num=now,bin=1;
			while (last)
			{
    
    
				bin*=10;
				if (last>=9) last-=9,num=bin*9+num;
				else num=bin*last+num,last=0;
			}
			ans=min(ans,num);
		}
2. When there is a carry in this sequence, how to find it?
There is a solution to the problem written like this:
最后我们只要判断那些x+k>9的数需要进位。
处理很简单只要把倒数第二位填8(避免了进位)。
再倒着贪心填9即可。
But I have never understood why I can be so greedy. This kind of greedy optimality is understandable, but the correctness has never been understood and will not prove. How to ensure that such filling can cover all situations?
Let us first set: the highest digit of the first number to the tens place is a, and the highest digit of the last number to the tens place is b. (a+1=b, because it is after the carry)
So, for the sum of digits, what is the relationship between a and b?
If there is no carry between a and b, then sum(a)+1=sum(b).
If there is a carry, then the last few bits of a must be consecutive 9s. When there are i consecutive 9s at the end, sum(a)-i*9+1=sum(b).
So we can enumerate how many consecutive 9s there are at the end, this will get the first number of the sequence.
Some students may ask, why do you want to enumerate how many consecutive 9s are there at the end? Isn't this also a conclusion? Isn't there no proof?
Fill in as many 9s as possible. This should be obvious, right? But we are not sure, after filling in a few 9s, whether there must be a corresponding sequence of numbers, so we enumerate the number of 9s.
else
		{
    
    
			int l=now; int len1=9-l+1;
			int r=(k+1)-len1-1; int len2=r-0+1;  
			//没有进位时的个位表示为:now-->9 ; 
			//进位后的个位表示为:0-->len2
			int last=n-(now*len1+(0+len1-1)*len1/2);
			if (last<0) continue;
			last=last-(0+r)*(r+1)/2;
			if (last<0) continue;
			
			for (register int i=0; i<=17; ++i)
			{
    
    
				int lastt=last+len2*9*i-len2;
				//由进位时,sum(a)-i*9+1=sum(b)得到
				//我们就把这个-i*9+1加回去,这样求得的答案就是第一个数的 最高位到十位了 
				if (lastt%(len1+len2)!=0) continue;
				lastt/=(len1+len2);
				if (lastt<9*i) continue;
				
				int num=now,bin=1;
				for (register int j=1; j<=i; ++j) 
				{
    
    
					bin*=10;
					lastt-=9;
					num=bin*9+num;
				}
				//一段连续的9以后,如果剩下的数位和还是比9大,那么我们是不可以填9了
				//不然就不满足枚举i个9的要求了
				//尽管这样的情况出现后可能是不最优解,但是是不是最优解这个问题
				//我们可以继续枚举9的个数,让下一次循环操作来判断即可。
				//所以我们这里要插入一个8
				//在插入8之后,那么就是尽量多的多填9就好了。 
				if (lastt>=8)
				{
    
    
					bin*=10;
					lastt-=8;
					num=bin*8+num;
					while (lastt)
					{
    
    
						bin*=10;
						if (lastt>=9) lastt-=9,num=bin*9+num;
						else num=bin*lastt+num,lastt=0;	
					}
				}
				else
				{
    
    
					bin*=10;
					num=bin*lastt+num,lastt=0;
				}
				ans=min(ans,num);
			}
		}
Complete code:
#include <bits/stdc++.h>
#define int long long
using namespace std;
int T,n,k,ans;

inline void solve()
{
    
    
	ans=1e18;
	for (register int now=0; now<=9; ++now)
	{
    
    
		if (now+k<=9)    //不进位时 
		{
    
    
			int last=n-(now*(k+1)+(1+k)*k/2);
			if (last<0 || last%(k+1)!=0) continue;
			last/=(k+1);
			int num=now,bin=1;
			while (last)
			{
    
    
				bin*=10;
				if (last>=9) last-=9,num=bin*9+num;
				else num=bin*last+num,last=0;
			}
			ans=min(ans,num);
		}
		else
		{
    
    
			int l=now; int len1=9-l+1;
			int r=(k+1)-len1-1; int len2=r-0+1;  
			//没有进位时的个位表示为:now-->9 ; 
			//进位后的个位表示为:0-->len2
			int last=n-(now*len1+(0+len1-1)*len1/2);
			if (last<0) continue;
			last=last-(0+r)*(r+1)/2;
			if (last<0) continue;
			
			for (register int i=0; i<=17; ++i)
			{
    
    
				int lastt=last+len2*9*i-len2;
				//由进位时,sum(a)-i*9+1=sum(b)得到
				//我们就把这个-i*9+1加回去,这样求得的答案就是第一个数的 最高位到十位了 
				if (lastt%(len1+len2)!=0) continue;
				lastt/=(len1+len2);
				if (lastt<9*i) continue;
				
				int num=now,bin=1;
				for (register int j=1; j<=i; ++j) 
				{
    
    
					bin*=10;
					lastt-=9;
					num=bin*9+num;
				}
				//一段连续的9以后,如果剩下的数位和还是比9大,那么我们是不可以填9了
				//不然就不满足枚举i个9的要求了
				//尽管这样的情况出现后可能是不最优解,但是是不是最优解这个问题
				//我们可以继续枚举9的个数,让下一次循环操作来判断即可。
				//所以我们这里要插入一个8
				//在插入8之后,那么就是尽量多的多填9就好了。 
				if (lastt>=8)
				{
    
    
					bin*=10;
					lastt-=8;
					num=bin*8+num;
					while (lastt)
					{
    
    
						bin*=10;
						if (lastt>=9) lastt-=9,num=bin*9+num;
						else num=bin*lastt+num,lastt=0;	
					}
				}
				else
				{
    
    
					bin*=10;
					num=bin*lastt+num,lastt=0;
				}
				ans=min(ans,num);
			}
		}
	}
	if (ans==1e18) puts("-1");
	else printf("%lld\n",ans);
}

signed main(){
    
    
	scanf("%lld",&T);
	while (T--)
	{
    
    
		scanf("%lld%lld",&n,&k);
		solve();
	}
return 0;	
}

Guess you like

Origin blog.csdn.net/Dove_xyh/article/details/108558090