POJ 1091 跳蚤
1 #include<stdio.h> 2 int prime[10]; //十个就够了,因为m最多有不超过10个素因子 3 long long pow(long long x,int y)//求x^y幂,用大整数 4 { 5 long long res=1; 6 while(y--) 7 res*=x; 8 return res; 9 } 10 int main() 11 { 12 int i,j,n,m,t,tol=0; 13 scanf("%d%d",&n,&m); 14 t=m; 15 long long res=pow(m,n); //必须用大整数 16 for(i=2;i*i<=m;i++)//计算素因子个数 17 { 18 if(m%i==0) 19 prime[tol++]=i; 20 while(m%i==0) 21 m/=i; 22 } 23 if(m!=1) //如果本身就是大于n开方的素数,需要加一,这点不要忘记 24 prime[tol++]=m; 25 for(i=1;i<(1<<tol);i++)//总共有1~2^tol-1个组合 26 { 27 int k=1; 28 int sum=0; 29 for(j=0;j<tol;j++)//巧妙利用二进制来查找到所有素因子组合构成的数 30 { 31 if(i&(1<<j)) 32 { 33 k*=prime[j]; 34 sum++; 35 } 36 } 37 if(sum&1) res-=pow(t/k,n);//假如含有素因子个数为奇数,则减去,否则加上 38 else res+=pow(t/k,n); 39 } 40 printf("%lld\n",res); 41 return 0; 42 }
根据数论的知识
如果存在x[1],x[2].....x[n],使得 data[1]*x[1]+data[2]*x[2]+......+data[3]*x[3]==1;,则,data[1],data[2],....data[n]最大公约数一定是1;
一共有 m^n张卡片,如果减去其中含有公约数的卡片剩下的就是所求的结果
举个例子 n=2, m=360; 360=2^3*3^2*5
结果 = (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 个。