Description
在一张卡片上面,有N+1个正整数,最后一个数是M,而前N个数都不超过M,设为a1,a2, a3, …, aN, 问是否存在整数x1,x2, x3, …, xN, x(N+1), 满足x1*a1 + x2*a2 +...+ xN*aN +x(N+1)*M = 1。
当确定N和M后,显然一共有M^N张不同的卡片。现在的问题是,在这所有的卡片中,有多少张满足上面条件。
Input
多组数据。两个整数N和M(N <= 10 , M <= 50), 最后的结果不超过2^63
Output
满足条件的卡片数。
SampleInput
2 4
SampleOutput
12
Hint
长整型请用long long
解题思路:(利用了容斥原理)
(1)题意:n+1个自然数,其中m是确定的,其他n个数都不超过m,有多少种方案使得a1x1+a2x2……+an+1xn+1=1.根据欧几里得,可知题目是要求有多少个这样的序列a1,a2……an+1,他们的最大公约数为1.由于其中一个数确定是m,而其他的数都小于等于m,所以我们只要把m分解质因数,如m=60,那么m分解得 m=2^2*3*5,利用容斥原理,总的可能数是m^n,m以内有2这个质因数的个数是m/2,所以序列包含2这个公因子的种类有(m/2)^n,依此类推……
(2)题意:具体解题步骤如下:
1、求出满m的所有质因子,存入数组num
2、求出总的序列个数吗m^n
3、设t(k)表示数列最大公约数为(k个质因子乘积)的数列的个数
f=m^n-t(1)+t(2)-t(3)+..(-1)^k*t(k);
答案 = (m ^ n) - (有公因数2的n元组)- (有公因数3的n元组)- (有公因数5的n元组)+ (有公因数2,3的n元组) +(有公因数2,5的n元组) + (有公因数3,5的n元组)- (有公因数2,3,5的n元组)。这个比公式形象些
有公因数d的n元组,每个位置上有 (m/d)个选择(1 ~ m里面有m/d个d的倍数),根据乘法原理,可以得出有公因数d的n元组有 (m/d)^n 个。
package OJ; import java.util.*; import java.math.*; public class P19_temp { static BigInteger one = BigInteger.ONE; static BigInteger zero = BigInteger.ZERO; static BigInteger per; static int n,m,total; static int[] s = new int[130000]; static int[] num = new int[130000];//存储m的质因子 static void getPrime(int m){ //求m的质因子 int i,j = 0; total = 0; for(i=2; i*i<=m; i++){ //这个平方需要注意一下 if(m%i==0){ while(m%i==0) m = m/i; num[total] = i; total++; } } if(m!=1){ num[total] = m; total++; //total表示实际质因子的个数 } } static BigInteger power(int m,int n){ //求m^n BigInteger power = new BigInteger(""+m); BigInteger k = power; for(int i=1; i<n; i++){ power = k.multiply(power); } return power; } static void get(int a, int b, int c){//a:在数组中的起始位置 b:含的个数 c:公共质因子个数; if(b==c){ int t = m; for(int i=0; i<c; i++){ t = t/s[i]; }//t表示每位上有几个包含质因子的数 per = per.add(power(t, n)); } else{//假如含有的质因子个数!=公共质因子数,s[b]入栈,递归;递归完成一次后,s[b]更新,递增一个由num[i]到num[i+1] for(int i=a; i<total; i++){ s[b] = num[i]; get(i+1,b+1,c); } } } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub BigInteger res; Scanner in = new Scanner(System.in); n = in.nextInt(); m = in.nextInt(); getPrime(m); res = power(m, n); for(int i=0; i<total; i++){ per = zero; get(0, 0, i+1);//包含i+1个质因子,有多少种组合 if(i%2==0) res = res.subtract(per);//假如i+1为奇数,符号为负 else res = res.add(per);//假如i+1为偶数,符号为正 } System.out.println(res); } }