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 个。

posted on 2013-03-25 14:22  小花熊  阅读(500)  评论(0编辑  收藏  举报

导航