POJ 1091 跳蚤 【容斥】【质因数分解】

题目:点击打开链接

题意:中文题

分析:题意可转化为,有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);
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值