Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 9381 | Accepted: 2822 |
Description
Input
Output
Sample Input
2 4
Sample Output
12
Hint
Source
这题挺不错的,综合的运用扩展欧几里德和容斥原理,不懂的最好先自行百度理解一下。
红色标记的便是主要的难点,理解了这题基本就没有什么问题了。
首先若想往前跳一步,由扩展欧几里德知识可知满足下列条件:
Gcd(x1,x2,x3,x4…xn,m)=1
所以答案就是所有的卡片最大公因数为1的种类数目,但是这样不好实现,于是我们考虑用所有的组合数M^N减去最大公因子不为1的卡片组合数。
而最大公因子不为1的卡片组合数的计算就涉及到容斥原理:
最大公因子不为1的卡片组合数 = 素公因个数为奇数个数的组合数目 - 素公因数个数为偶数个数的组合数目。
AC代码:
#include<cstdio> #include<cstring> using namespace std; /**ANS=用所有的组合数-素因子为奇数个的集合+素因子为偶数个的集合**/ int P[100],k,n,m,A[100]; long long num; long long Pow(int x,int n) { long long y=1; while(n--) y*=x; return y; } void findprime(int x)//找出所有素因子存入Prime数组 { k=0; for(int i=2;i*i<=x;i++) { if(x%i==0) { P[k++]=i; while(x%i==0) x/=i; } } if(x>1) P[k++]=x; } void dfs(int a,int b,int c)//找出素因子个数为c个所有情况,b为已经确定的个数,a为初始寻找数,用A数组存储找到的数 { if(b==c)//当找完c个公因数数时,确定有多少个包含这几个公因数的数 { int x=m; for(int i=0;i<c;i++) x/=A[i]; num+=Pow(x,n); //printf("num=%I64d\n",num); } else { for(int i=a;i<k;i++) { A[b]=P[i]; //printf("A[%d]=%d\n",b,A[b]); dfs(i+1,b+1,c); } } } int main() { while(scanf("%d%d",&n,&m)==2) { findprime(m); long long ans=Pow(m,n); for(int i=1;i<=k;i++) { num=0; dfs(0,0,i); if(i%2) ans-=num; else ans+=num; } printf("%I64d\n",ans); } return 0; }