【题意】 我们要找出最小的正整数n满足——
a*S(n)==b*S(2n)
a*S(n)==b*S(2n)
a,b的范围都在[1,100]
【分析&推导】
首先可以有这样的基础性结论:
设gcd(a,b)=g, 我们可以先使得b=b/g, a=a/g
S(n):S(2n)==b:a,那么我们有S(n):S(2n)=b:a。
然后,一个好的做法是,我们研究本质问题。
我们发现,如果一个digit是0~4,那么*2的效益是完全获得的。
如果一个digit的是5~9,那么*2后会损失9的收益。
这里解释一下为什么会损失9的收益
对于digit是5~9的,*2之后会变成两位,即10+x,而计算S(n)的时候,10只能被记为1,故损失了9
a*S(n) == b*S(2n),
我们假设有l的长度是[0,4]范围,有L的长度是[5,9]范围
那么显然满足:
S(2n)=S(n)*2-L*9
替换一下——
a*S(n) == b*(2S(n)-L*9)
a*S(n) == 2b*S(n) -L*9*b
(2b-a)*S(n) == L*9*b
即——
9*b:2b-a = S(n):L
也就是说,我们得到了S(n)与L的比例关系。
然后模拟一遍即可。
怎么模拟呢?
我们不妨假设答案n仅有长度为L,且每一位都是5
然后得到了把数位和sum分撒出去。
对于sum余下的数值,我们依次加到尾巴上。
如果sum最后把长度为L的字串都填充为'9'之后,还有剩余,那么在前面贪心填充。
#include <stdio.h>
#include <iostream>
using namespace std;
int ans[10005];
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
int main(){
int t,a,b,m,n,k;
scanf("%d",&t);
while(t--){
scanf("%d%d",&a,&b);
n=9*b,m=2*b-a;
if(m<0||5*m>n){
puts("0");
}
else if(m==0){
puts("1");
}
else{
k=gcd(n,m);
n/=k;
m/=k;
n-=5*m;
for(int i=0; i<m; i++,n-=k){
k=min(4,n);
ans[i] = k+5;
}
while(n>4){
ans[m++]=4;
n-=4;
}
if(n)
ans[m++]=n;
// for(int i=0; i<m-1; i++){
// printf("%d",ans[i]);
// }
// printf("%d\n",ans[m-1]);
for(int i=m-1; i>=0; i--) printf("%d",ans[i]);
puts("");
}
}
return 0;
}