1. 程式人生 > >hdu 5710 digit—sum數論

hdu 5710 digit—sum數論

題目連結 hdu 5710
思路題

/*竟然一道題想了兩天 
對於n中的任何一個數位x,若x為0-4,則因為沒有進位,
所以在S(2n)中貢獻為2x;若x為5-9,則由於其超過10,在S(2n)中貢獻為2x-10+1.
a*S=b*(2S*9L)
則
(2b-a)S=9*b*L
s=9bl/(2b-a);
s就是s(n),a,b就是題目中給的ab
l是某一位上為5-9的 位數 
1. a=2b,則L=0,S為任意值。可得最小的n=1; 
2. a>2b,則L<0,矛盾!則無滿足的n,輸出0; 
3. a<2b, S=9bL/(2b-a)≤5L (至少有L個5),即必須滿足 b≤5a ,否則無滿足的n,輸出0。
a趨近於0,9b/2b<10b/2b,利用了放縮 
繼續討論上述第三種情況,由於分母為2b-a,L週期性地使得右邊式子可以整除,現在只要求出最小的L,
列舉範圍從1到2b-a必定會有滿足的L。 
得到一組滿足的(L,S),構造最小的n。最小的n,最小的l首
先要在後L位塞滿5,剩下的(S-5L)開始從個位到高位塞4,直到塞完為止。
故 S(n)=k*(9b) ,
L=k*(2b-a)同時,由於要求 n 最小,可知 k 取 1 時最小。
在已有 S(n)以及 L 的情況下,求 n ?
首先構造長為 L ,每個字元均為 5 (由於 L 個數字必須 >= 5)的字串,
同時 S(n)-=5×L 。對於多餘的 S(n) ,
為使得 n 儘可能小(即串長最小,大的數字儘可能向個位數靠攏)。故優先將串尾的字元增長到 9 。
若長為 L 的字串已經全部為 9 。此時不得不增加串長,則優先在串首增加 4 (不在 L 個數字中的均 <= 4),直到 S(n)S(n) 全部用盡。

*/

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
	int t,a,b,s,l,GCD,add;//add代表加的值 
	scanf("%d",&t);
	while(t--){
		scanf("%d%d",&a,&b);
		if(a>2*b||b>5*a) printf("0\n");
		else{
			l=2*b-a;
			s=9*b;
			GCD=__gcd(l,s);
			l/=GCD;
			s/=GCD;
			string ans=string(l,'5');//先把l裡面都換成5;
			s-=5*l;
			for(int i=ans.size()-1;i+1;i--){//要想使位數比較小,需要各位為9 
				add=min(s,4);//如果sn>4,5+4=9,如果小於4 ,直接 加原來的 
				ans[i]+=add;
				s-=add;
			}
			while(s){//如果變成9 還不夠,那就要把串長增加
			    add=min(s,4);
			    ans=char(add+'0')+ans;
			    s-=add;
		    }
		    printf("%s\n",ans.c_str());
		    //C語言中沒有string類,字串使用char指標來實現的。
            //C與C++本身就是一家,為了讓它們在一定程度上可以通用,就有了.c_str()函式。
		}
		
	}
	return 0;
}