code forces 1373 E - Sum of Digits 思维分析性质

博客探讨了Code Forces 1373E问题中关于数字之和的性质,指出在大多数情况下,序列f[x+1] = f[x] + 1。然而,当x+k导致进位时,序列会分为两个等差数列。文章通过枚举个位和进位次数来解决进位导致的复杂情况,并给出了构造序列的策略,确保整体数值尽可能小。
摘要由CSDN通过智能技术生成

容易发现:大部分情况下f[x+1]=f[x]+1;

如果全部f[x],满足这个性质,则直接可以求出f[x]进行构造。

但由于x+k会发生进位,f[x]出现两个等差数列,中间出现断层。

且只会出现2个等差数列,因为k小于等于9,即x最多进位1次。(个位往前进位)

所以我们枚举个位c,如果k+c<=9,则不会发生进位。直接用等差数列求出f[x]即可。(f[x]+f[x]+1+k)*(k+1)/2 。

然后从个位进行构造,低位尽量取大数,这样高位可以取少一点,使得整体尽量小。

否则的话再枚举个位前面9的个数t,(因为个位发生进位,前面是9的话会发生连环进位)。

进位导致第二个等差数列的首项为第一个等差数列末项  +1 - 9*(t+1).

然后就可以求出f[x]了。  

构造同上,不过注意满足后t+1位都是9.然后t+2位不能为9.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
/*
int head[M],cnt=1;
void init(){cnt=1,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
*/
ll mi;
int main()
{
	ios::sync_with_stdio(false);
  	cin.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
		mi=2e18;
		int n,k;
		cin>>n>>k;
		bool f=false;
		for(int c=0;c<=9;c++)//枚举个位
		{
			if(c+k<=9)
			{
				int now=n-(1+k)*k/2;
				if(now%(k+1)==0)
				{
					
					now/=(k+1);
					ll tp=c,b=1;
					now-=c;
					if(now<0)continue;
					while(now>9)
					{
						b*=10;
						tp+=b*9;
						now-=9;
					}
					if(now)b*=10,tp+=b*now;
				//	cout<<c<<"  "<<tp<<"  "<<mi<<endl;
					mi=min(tp,mi);f=true;
				}
				continue;
			}
			for(int t=0;t<=15;t++)//十位之前连续9的个数
			{
				
				int now=n+(t+1)*9*(c+k-9)-(1+k)*k/2;
				
				if(now%(k+1)==0)
				{
					now/=(k+1);
					ll tp=c,b=1;now-=c;
					for(int j=1;j<=t;j++)
					{
						b*=10;
						tp+=b*9;
						now-=9;
					}
					if(now<0)continue;
					if(now>=8)b*=10,tp+=b*8,now-=8;
					while(now>9)
					{
						b*=10;
						tp+=b*9;
						now-=9;
					}
					if(now)b*=10,tp+=b*now;
				//	cout<<c<<"  "<<t<<"   "<<tp<< endl;
					mi=min(mi,tp);f=true;
				}
				//f[x]*(k+1)+(1+k)*k/2-(t+1)*9*(c+k-10)=n
			 } 
		 }
		 if(f)cout<<mi<<endl;
		 else cout<<-1<<endl;
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值