这道题做的我 七窍生烟 半死不活  怒斥UVA无人性
明白了longlong 的重要性
题目大意
给一个真分数a/b,把他拆分成1/x1+1/x2+1/x3……
若有多种情况,输出拆分出分数最少的一种
如果还有多种情况,输出分母第一大最小,如果还不行,第二大最小,以此类推。
第一行输入数据组数 t
注意,每行输入这几个数 :
分子a 分母b 不能用的分母k个 然后后面会有k个不能用给的整数
解题过程
被卡了两个半小时,代码越来越题解化。
不过下面那个题解没说的太清楚,这里附上几个证明。
证明1.  分母下界取值
∵ a/b 为真分数 ,a,b,k均为整数
∴ a<b
设正整数x,y ax+y=b
发现 floor(b/a)=floor( (x * a+y) /a )=floor(x * a/a)+floor(y/a) = x
以及 floor(b/a)<=b/a
∴ floor(b/a)=x
∴ x+1 > b/a , ∴floor(b/a)+1>b/a
∴ 1/(x+1) < a/b 又 1/floor(b/a)=1/x >=a/b
∴ x+1就是最小的 k 使得 1/k < a/b
∴ k=floor(b/a) + 1
证明2.  分母上界取值
if(a * i>=b * (mmxdep-dep+1)) return ;
证明过程
a * i >= b * (mmxdep-dep+1)
a >= (b * mmxdep-dep+1)/i       两边除i
a/b >= (mmxdep-dep+1) /i         两边除b
a/b >= (1/i ) * (mmxdep-dep+1)   换一个等价写法
也就是说,剩下即使按照每一个分数都是比最大还大的i/1会留下,因此直接剪枝
通分的方式
这句话在通分: na=a * i-b,nb=b * i;
当前数值为a/b,我们要从中抽出1/i
原式 = a/b-1/i
  =ai/bi-b/bi
  =(ai-b)/bi
na存的是左边分子,nb存的是右边分母,这个过程相当于通分
我觉得应该差不多了,那就上代码吧
代码
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 
 | g#include<iostream>#include<cmath>
 #include<cstdio>
 #include<cstring>
 #include<set>
 
 #define re int
 
 using namespace std;
 
 long long n,t,k,mmxdep,f;
 long long bs[100500],tmp[100500],mutia,mutib,w[100500];
 
 set <long long> p;
 
 int pd()
 {
 for(re i=mmxdep;i>=1;i--)
 {
 if(bs[i]!=w[i])
 {
 if(bs[i]==0) return 0;
 if(bs[i]>w[i]) return 0;
 return 1;
 }
 }
 return 1;
 }
 
 long long gcd(long long a,long long b)
 {
 if(b==0) return a;
 else return gcd(b,a%b);
 }
 
 void dfs(int dep,long long a,long long b,long long lasi)
 {
 long long i;
 if(dep==mmxdep)
 {
 if(b%a||p.count(b/a)) return ;
 w[dep]=b/a;
 if(!pd()) memcpy(bs,w,sizeof(w));
 
 f=1;
 return ;
 }
 for(i=max(lasi,b/a+1);;i++)
 {
 if(p.count(i)) continue;
 if(a*i>=b*(mmxdep-dep+1)) return ;
 long long na=a*i-b,nb=b*i;
 long long fri=gcd(na,nb);
 w[dep]=i;
 dfs(dep+1,na/fri,nb/fri,i+1);
 }
 return ;
 }
 
 int main()
 {
 int i,j;
 scanf("%lld",&t);
 for(i=1;i<=t;i++)
 {
 long long t1;
 p.clear();
 scanf("%lld %lld %lld",&mutia,&mutib,&k);
 for(j=1;j<=k;j++)
 scanf("%lld",&t1),p.insert(t1);
 for(mmxdep=2;;mmxdep++)
 {
 memset(bs,0,sizeof(bs));
 dfs(1,mutia,mutib,mutib/mutia+1);
 if(f) break;
 }
 printf("Case %d: %lld/%lld=1/%lld",i,mutia,mutib,bs[1]);
 for(j=2;j<=mmxdep;j++)
 printf("+1/%lld",bs[j]);
 printf("\n");
 memset(bs,0,sizeof(bs));
 f=0;
 }
 return 0;
 }
 
 |