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;
}
posted @ 2019-08-16 17:38  voids5  阅读(72)  评论(0编辑  收藏  举报