POj-1091 跳蚤
原题链接:http://poj.org/problem?id=1091
题目大意:给你两个数n和m;总共有m^n张卡片,每张卡片上有n+1个数字,然后根据卡片上的数字可以向左跳也可以向右跳,每个数字跳的次数任意,直到跳达刚开始左边一个单位的地方
解题思路:把卡片上的数字用x1,x2,x3…xn,m表示,跳的次数可以用a1,a2,a3…an+1表示,于是可以得到:
a1x1+a2x2+…+anxn+an+1m=1;
这个式子是不是很像扩展欧几里得里的ax+by=gcd(a,b)=1;所以我们就可以想到只要保证gcd(a1,a2,a3…an+1)==1,就说明该卡片可以完成任务。而这样正着求比较难求(反正我不会),我们可以求出不满足的即gcd(a1,a2,a3…an+1)!= 1,即不互质,因为每张卡片都有m,那只要有一个数和m不互质就可以了,可以用到唯一分解定理来分解m,然后反着用容斥定理,奇减偶加;即可求出答案。
Code:
#include<iostream>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
vector<int>ve;
void getprime(int m){//得到m的质因子
ve.clear();
for(int i=2;i*i<=m;i++){
if(m%i==0){
ve.push_back(i);
}
while(m%i==0){
m/=i;
}
}
if(m>1) ve.push_back(m);
}
ll ksm(ll m,ll n){//快速幂模板
ll res=1;
while(n){
if(n&1) res=res*m;
n>>=1;
m=m*m;
}
return res;
}
int main(){
int n,m;
cin>>n>>m;
getprime(m);
ll ans=ksm(m,n);//卡片总数
// cout<<ve.size()<<endl;
for(int i=1;i<(1<<ve.size());i++){//(1<<ve.size()) 表示2^ve.size()次方
ll cnt=0,sum=1;
for(int j=0;j<ve.size();j++){
if(1&(i>>j)){
cnt++;
sum*=ve[j];
}
}
if(cnt&1) ans-=pow(m/sum,n);//奇减偶加
else ans+=pow(m/sum,n);
}
cout<<ans<<endl;
return 0;
}
七月在野,八月在宇,九月在户,十月蟋蟀入我床下