InterviewStreet题目(1)

题目描述,

给定等式1/x+1/y=1/(N!),求当x>0且y>0的时候,使等式成立的解(x,y)的个数mod1000007。其中1<=N<=10^6。

题目分类:Math

题目来源:Interview Street

解:

首先明确一点,(2,1)和(1,2)诸如此类的算是不同的解。其次明确无论是具体解的个数还是X、Y以及N!均无法在计算机中表示(太大了),因此结合题目的分类,基本上是要从数学的角度来找突破点。

先把1/x+1/y=1/(N!)化简成y=f(x)的形式。

为了方便,设1/(N!)=k。所以化简可得y=x/(kx-1)。还不够直观,再化简得:y=1/k+1/(k^2)*(1/(x-1/k))。所以题目变成求函数y=1/k+1/(k^2)*(1/(x-1/k))在第一象限的且x,y都是整数的点的个数。

分析此函数可以看出,这个函数是将函数y=1/(k^2*x)在直角坐标系上向右和向上平移了1/k距离,而由原函数图像可知(单调递减、过0点、在x=1/k处达到无穷,很容易画出),原函数x,y在第一象限且均为整数的点和函数y=1/(k^2*x)在第一象限且x,y均为整数的点的数量相同,又因为1/k=N!为整数,所以问题转化成求函数y=1/(k^2*x)在第一象限的点的个数,即求使xy=1/K^2=N!*N!成立且x,y均为正整数的解的个数。

根据一些数论知识我们可以知道,任何一个整数都能表示成(a1^x1)*(a2^x2)*(a3^x3)*.......的形式,其中均是自然数,a是素数。

所以我们尝试将N!*N!表示成这种形式。

首先用素数筛筛出小于N的所有素数(O(n)复杂度,或许还要多点),然后对于所有小于N的自然数,使用求出的素数表去约,直到约成1位置,就可把N!表示成都表示成(a1^x1)*(a2^x2)*(a3^x3)*.......的形式,时间复杂度约为(O(n*sqrt(n)),博主不是很确定)。

然后即可知道N!*N!的形式是(a1^(2*x1))*(a2^(2*x2))*(a3^(2*x3))*.......,也就是个平方关系然后再带进去化简。

显然,对于一个x有唯一的y使x*y=N!*N!,因此只需要确定x的数量即可(不用担心会重复,因为(1,2)(2,1)算不同的解。

所以根据排列组合的乘法原理,x的表示方法有(2*x1+1)*(2*x2+1)*(2*x3+1)。。。。种,道理即是为了确定x,我们可以选取[0,x1]个a1,再选取[0,x2]个a2,以此类推

(+1是因为考虑可以选0)。

至此,题目已经完成,输出结果即可。

附上java代码一段仅供参考(博主很懒没有用筛,所以15个用例有一个超时了,改成筛应该就没问题了):

import java.io.*;
import java.util.ArrayList;


public class Solution{
	
	public static void main(String[] argvs)
	{
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		
		try {
			int N=Integer.valueOf(br.readLine());
			ArrayList prime=new ArrayList();
			if(N==1)
			{
			System.out.println(1);
			return;
			}
			for(int i=2;i<=N;i++)
			{
			if(isPrime(i)==true)
			prime.add(i);
			}
			int[] k=new int[prime.size()];
			for(int i=2;i<=N;i++)
			{
				int t=i;
				for(int j=0;j<=prime.size()-1;j++)
				{
					if(t%prime.get(j)==0)
					{	
						t/=prime.get(j);
						k[j]++;
						j=-1;
					}
					if(t==1)
						break;
				}
			}
			long result=1;
			for(int i=0;i<=k.length-1;i++)
			{
				result*=(2*k[i]+1);
				result%=1000007;
			}
			System.out.println(result);
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	private static boolean isPrime(int n)
	{
		for(int i=2;i<=Math.sqrt(n);i++)
		{
			if(n%i==0)
				return false;
		}
		return true;
	}
}


 

你可能感兴趣的:(算法与数学)