题目
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.youkuaiyun.com/DorMOUSENone/article/details/71223368
题解
如果数位在0-4之间,乘以2的数位和,就是原数乘以2
如果数位在5-9之间,乘以2所得数的数位和,相对于原数乘以2来说,减少了9
所以设数位在5-9之间的长度为L,
根据定义,有
代入得,
,
化简有,
即,
如令S(n)最小,则只需k=1,
同时注意到,如果k==1都没有解,则k>1不可能有解
即
现在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;
}