poj 1091 跳蚤【扩展欧几里得、容斥原理】

poj 1091 跳蚤【扩展欧几里得、容斥原理】

 

http://acm.pku.edu.cn/JudgeOnline/problem?id=1091

 

【题目大意】

输入整数n和m,找n个数字(都小于等于m),加上m共n+1个数字,使得这个n+1个数字满足存在x1…xn+1使得下列方程成立:a1*x1+a2*x2+a3*x3+…an*xn+m*xn+1=1,问共有多少组这样n+1个数字。

 

【提交情况】

Wa三次,开始用的math头文件中提供的次方,经过double和long long的多次相互转化,丢失精度,导致无法通过。后自己写了个计算long long的次方的函数即可通过。

 

【解题思路】

根据扩展欧几里得,可以得知若想要a1*x1+a2*x2+a3*x3+…an*xn+m*xn+1=k成立,那么需要a1 a2 ….an m 的最大公约数是k,两边都除以k得到的就是我们想要求的那个方程。其实最大公约数另一个定义就是满足存在x1、x2……xn+1使得a1*x1+a2*x2+a3*x3+…an*xn+m*xn+1=k成立的最小整数,也就是说这是充要条件,其实题目就是问a1 a2……an、m共有多少组这样的组合使得最大公约数是1。

实际上就是求有多少组这样的数互质,由于m固定,所以只需要找到前n个数字不都含有m的某个质因子,有多少种组合即可。

先将m分解质因子,得到以后根据容斥原理进行计算:去掉都含其中一个质因子的,假设质因子为x,则一个位置的数去掉含x的质因子的,其实根数为m/x,然后加上含两个的……经过计算即可得到结果。

 

【AC的代码】

#include <iostream>

using namespace std;

 

typedef long long i64;

i64 pf[110000],pfNum,mn,d[110000],n,m,t,change;

 

i64 ipow(i64 dn,i64 up)

{

                                    i64 ret=1;

                                    while(up--) ret*=dn;

                                    return ret;

}

 

void getChange(i64 btm,i64 now,i64 top)

{

                                    i64 get=m,i;

                                    if(now==top)

                                    {

                                     for(i=0;i<top;i++) get/=d[i];

                                     change+=i64(ipow(get,n));

                                    }

                                    else for(i=btm;i<pfNum;i++) d[now]=pf[i],getChange(i+1,now+1,top);

}

 

int main()

{

                                    i64 i,ans,mm;

                                    while(cin>>n>>m)

                                    {

                                     pfNum=0; mm=m;

                                     for(i=2;i*i<=mm;i++)

                                     {

                                               if(mm%i==0)

                                               {

                                                        while(mm%i==0) mm/=i;

                                                        pf[pfNum++]=i;

                                               }

                                     }

                                     if(mm!=1) pf[pfNum++]=mm;

                                     ans=mn=i64(ipow(m,n));

                                     for(i=0;i<pfNum;i++)

                                     {

                                               change=0;

                                               getChange(0,0,i+1);

                                               if(i%2) ans+=change;

                                               else ans-=change;

                                     }

                                     cout<<ans<<endl;

                                    }

                                    return 0;

}

posted on 2010-03-05 10:27  liugoodness  阅读(161)  评论(0)    收藏  举报

导航