嗯,到了期末复习,额,期末预习的阶段了,白天忙着预习和还之前物理实验的债,晚上就给自己开点小灶、开开脑洞吧。
回到正题,既然说到某个数的因子,让我们先来看一道题吧。
对于一个整数n,我们求出1/n=1/a+1/b的所有a和b的正整数解的个数(但a=x,b=y和a=y,b=x看作同一组解)
解法1:首先让我们对1/n进行一系列的化简:
设正整数k,并且因为解不重复,不妨假设a>=b:
1/n=1/(n+k)+k/n*(n+k)
=1/(n+k)+k/(n^2+n*k)
=1/(n+k)+1/(n^2/k+n)
=1/(n+k)+1/(n+n^2/k)
即a=n+k,b=n+n^2/k。因为a>=b,所以k<=n^2/k,即k<=n。
又因为a,b均为正整数,那么n^2/k必为整数,即k为n^2的因子。
所以,满足条件的k的个数为n的因子数+1,也就是这道题解的个数。
解法2:
事实上,我们把n分解质因数之后,在n的所有约数中任取两个,就可以得到一组解。
例如:n=18,18的约数共有六个1,2,3,6,9,18。只要把分子分母都乘以这个分母的任意两个约数的和,就可以把一个分数拆分成两个分数的和。
可以看出,由于每次所选用的两个约数不同,所得的解也不相同。但是当选用的四个约数成比例时,他们的解就相同。如:选用1和2,3和6,9和18;或选用2和3,6和9时,解就相同。
所以,这种方法在实现时就需要我们在遍历枚举n的约数过程中,两个数的最大公约数必须为1才行。
——————————— 华丽的分割线 ———————————————
嗯,如果上面的问题很容易明白的话,那么接下来让我们给问题增加点难度。
同样的,还是求分数拆分的问题,对于两个正整数n,m(m<n),对于m/n=1/a+1/b有多少组解呢?(a=x,b=y和a=y,b=x依旧看作同一组解)
我们这里继续延续上一题第二种解题方法的思想,这里的问题就是m不再为1了,该如何解决对约数枚举的取舍呢?
由上题的分母约数来看,对于m/n而言,上下同乘以某两个n的约数和,想得到两个分子为1的分数,就必须将m消除,因此,我们只需要对每组枚举再加一步if(约数和%m==0)的判断即可。
我想,当以上内容都了解之后,就可以尝试着完成一下HOJ 11537了,
题目链接:http://202.197.96.79:8080/online/?action=problem&type=show&id=11537&courseid=135
#include<cstdio>
using namespace std;
int m,n;
int a[10010];
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int cases=0;
while(~scanf("%d%d",&m,&n)){
int ans=0,temp=0,i,k;
k=gcd(m,n),m/=k,n/=k;
for(i=1;i*i<n;i++){
if(n%i==0)
a[temp++]=i,a[temp++]=n/i;
}
if(i*i==n) a[temp++]=i;
if(m<=n)
for(int i=0;i<temp;i++)
for(int j=i;j<temp;j++)
if(gcd(a[i],a[j])==1)
if((a[i]+a[j])%m==0)
ans++;
printf("Scenario #%d\n",++cases);
if(ans>1) printf("Find %d solutions\n",ans);
else if(ans==1) printf("Only one solution\n");
else if(ans==0) printf("No solution\n");
}
return 0;
}
刚写完寻思试试去,表示OJ给了个SYSTEM FAULT。表示郁闷。。不过目测应该可以过,嗯