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) 收藏 举报