题目:点击打开链接
题意:中文题
分析:题意可转化为,有n个数,每个数都小于等于m且允许重复,gcd(所有数)==1,求这n个数的所有满足条件的排列组合。求出gcd==1的个数难易实现,因此可以先求出gcd!=1的个数,即所有的数都不互质,易得这些数不与m互质,即可以由m的质因数推导出来,把m的质因数保存。取出k个质因数,相乘的数也是不与m互质,然后在1~m内,一共有 m/该数 个数与该数不互质,因为允许重复的数,所以该个数取n次方即为取出k个质因数相乘会产生的情况,一共取1到m个质因数,运用容斥原理求出不互质的总个数,再用总情况(m的n次方)减去不互质的排列个数即可。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define sqr(x) ((x)*(x))
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll INF = 1e18;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=10010;
const ll MOD=1000000007;
const double eps=1e-3;
const double pi=acos(-1.0);
using namespace std;
int n;
ll m,ans;
vector<int>fac;
void getfac(int m)
{
for(int i=2;i<=m/i;i++)
{
if(m%i==0) fac.push_back(i);
while(m%i==0) m/=i;
}
if(m>1) fac.push_back(m);
}
ll qpow(ll x,int n)
{
ll ans=1;
while(n)
{
if(n&1) ans*=x;
x*=x;
n>>=1;
}
return ans;
}
ll dfs(int idx,int cnt,ll num,int sum)
{
if(cnt==sum) return qpow(m/num,n);
ll res=0;
for(int i=idx;i<(int)fac.size();i++)
res+=dfs(i+1,cnt+1,num*fac[i],sum);
return res;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
ans=0;
getfac(m);
for(int i=0;i<(int)fac.size();i++)
{
ll tmp=dfs(0,0,1,i+1);
if(i%2==0) ans+=tmp;
else ans-=tmp;
}
ans=qpow(m,n)-ans;
printf("%I64d\n",ans);
}
}