分数拆分
Time Limit: 4000/2000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
任何一个分数都能才成若干个单位分数(形如1/a的, a是自然数)的和。
对于一个分数 ab ab,表示方法有很多种,但是哪种最好呢?
首先,加数少的比加数多的好,其次,加数个数相同的,最小的分数越大越好,如果还是相同,那么第二小的分数越大越好,依次类推下去。
例如对于 1945 1945,下列方法都是合法的:
1945=13+112+1180 1945=13+112+1180
1945=13+115+145 1945=13+115+145
1945=13+118+130 1945=13+118+130
1945=14+16+1180 1945=14+16+1180
1945=15+16+118 1945=15+16+118
但是最好的是最后一种,因为 118 118比 1180 1180, 145 145, 130 130, 1180 1180都大。
现在给出 a,b a,b( 0<a<b<1000 0<a<b<1000),求最好的表达方式。
Input
第一行有一个整数 T T,表示有 T T( T≤50 T≤50)组测试数据,每组测试数据为一行包含 a,b a,b( 0<a<b<1000 0<a<b<1000)。
Output
每组测试数据若干个数,自小到大排列,依次是单位分数的分母。
Sample input and output
Sample Input | Sample Output |
---|---|
1 19 45 | 5 6 18 |
Source
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N = 1005;
int T,a,b,md,f;
ll v[N],ans[N];
ll gcd( ll a, ll b ){
return b == 0 ? a : gcd( b, a%b );
}
int minn( ll a, ll b ){
return b/a + 1;
}
bool cmp( int d ){
for( int i = d; i >= 0; i-- ) if( v[i] != ans[i] ) {
return ans[i] == -1 || v[i] < ans[i];
}
return false;
}
bool dfs( int dep, int fa, ll x, ll y ){
if( dep == md ){
if( y % x ) return false;
v[dep] = y/x;
if(cmp(dep)) memcpy(ans,v,sizeof(ll)*(dep+1));
return true;
}
bool flag = false;
fa = max( fa, minn(x,y) );
for( int i = fa; ; i++ ){
if( y * (md+1-dep) <= x * i ) break;
v[dep] = i;
ll xx = x * i - y;
ll yy = y * i;
ll g = gcd(xx,yy);
if(dfs( dep+1, i+1, xx/g, yy/g )) flag = true;
}
return flag;
}
int main(){
scanf("%d", &T);
while( T-- ){
f = 0;
scanf("%d%d", &a, &b);
for( md = 1; md <= 100; md++ ) {
memset(ans, -1, sizeof(ans));
if(dfs(0, minn(a, b), a, b)){
f = 1;
break;
}
}
if(f) {
for( int i = 0; i <= md; i++ )
printf("%d ", ans[i]);
puts("");
} else printf("-1\n");
}
return 0;
}