hdu5710 Digit-Sum(构造+贪心)

题目

S(n)定义为一个数的各数位之和

给定a,b(0<a,b<101),

求满足a*S(n)==b*S(2n)的最小的n

如果无解输出0

思路来源

https://www.cnblogs.com/wenruo/p/5562100.html

https://blog.csdn.net/DorMOUSENone/article/details/71223368

题解

如果数位在0-4之间,乘以2的数位和,就是原数乘以2

如果数位在5-9之间,乘以2所得数的数位和,相对于原数乘以2来说,减少了9

 

所以设数位在5-9之间的长度为L,

根据定义,有S(2n)=S(n)*2-9*L

代入a*S(n)=b*S(2n)得,

a*S(n)=b*(S(n)*2-9*L)

化简有,\tfrac{S(n)}{L}=\tfrac{9b}{2b-a}

 

S(n)=k*9b,L=k*(2*b-a)

如令S(n)最小,则只需k=1,

同时注意到,如果k==1都没有解,则k>1不可能有解

S(n)=9b,L=(2*b-a)

 

现在n最短的长度为L,而有L长度的数位需要在5-9之间

所以我们先构造出一个全为5的,长度为L的数,

特别地,L为负或S不足5*L时,不能构造

 

如果S(n)还有剩余,优先从低位把5变大,直到9,

如果所有的位都被变成了9,S(n)还有剩余

说明只能从更高位增添1-4的值(肯定不能让9开头),

S(n)有余前提下,构造的位数越少越好,优先填4,直至S(n)为0

心得

也算是学会了一点string的用法叭

①string(L,‘5’)

②res.c_str()直接用于printf输出

③res='A'+res,用于前面插入单个字符

代码1

#include<iostream>
#include<cstring>
#include<cmath> 
#include<algorithm> 
using namespace std;
const int maxn=1e4+10;
int t,a,b,ans[maxn];
int S,L,d,num;
int gcd(int a,int b)
{
	return b?gcd(b,a%b):a; 
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&a,&b);
		S=9*b;L=2*b-a;
		if(L<0||5*L>S)
		{
			puts("0");
			continue;
	    }
	    d=gcd(S,L);
		S/=d,L/=d;
		num=L;
		for(int i=1;i<=L;++i)ans[i]=5;
		S-=5*L;
		for(int i=1;i<=L;++i)
		{
			int v=min(S,4);
			ans[i]+=v;
			S-=v;
		}
		while(S)
		{
			int v=min(S,4);
			ans[++num]=v;
			S-=v;
		} 
		for(int i=num;i>=1;--i)
		printf("%d",ans[i]);
		puts("");
	}
	return 0;
}

代码2(String的写法)

#include<iostream>
#include<cstring>
#include<cmath> 
#include<algorithm> 
using namespace std;
int t,a,b;
int S,L,d,num;
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&a,&b);
		S=9*b;L=2*b-a;
		if(L<0||5*L>S)
		{
			puts("0");
			continue;
	    }
	    d=__gcd(S,L);S/=d,L/=d;
		num=L;
		string res=string(L,'5');
		S-=5*L;
		for(int i=res.size()-1;i+1;--i)
		{
			int v=min(S,4);
			res[i]+=v;
			S-=v;
		}
		while(S)
		{
			int v=min(S,4);
			res=char(v+'0')+res;
			S-=v;
		} 
		printf("%s\n",res.c_str());
	}
	return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值