POJ 1091 跳蚤

来源:互联网 发布:煲机音量开多大合 知乎 编辑:程序博客网 时间:2024/05/03 21:41

题意实质是 求给出了n和m,要求出满足最大公约数(x1,x2,...,xn,m)=1的x1,...,xn的组数sum,其中必须满足0<= x1,x2,...,xn <= m。

先求出 sum = m^n 然后减去 最大公约数>1的组数 即求出m的所有约数

对于每个约数fac[i]  每个x有m/fac[i]种选择

再根据容斥原理 减去由奇数个质因子组成的约数 加上由偶数个质因子组成的约数

本题应用大数 不过long long能过

代码如下

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;

struct data
{
    int num,v;
    bool operator <(const data &p)const
    {
        return num<p.num;
    }
}fac[50];

ll mypow(int m,int n)
{
    ll ans=1;
    while(n--)
    {
        ans*=m;
    }
    return ans;
}

int find_factor(int m)
{
    int i,j,cnt;
    cnt=0;
    for(i=2;i*i<m;i++)
    {
        if(m%i==0)
        {
            fac[cnt++].num=i;
            fac[cnt++].num=m/i;
        }
    }
    if(i*i==m)
    {
        fac[cnt++].num=i;
    }
    fac[cnt++].num=m;
    
    sort(fac,fac+cnt);
    
    for(i=0;i<cnt;i++)
    {
        bool prime=true;
        int k=0;
        for(j=0;j<i;j++)
        {
            if(fac[j].v==1&&fac[i].num%fac[j].num==0)
            {
                k++;
                prime=false;
                if(fac[i].num%(fac[j].num*fac[j].num)==0)
                {
                    k=0;
                    break;
                }
            }
        }
        if(prime)
        {
            fac[i].v=1;
        }
        else
        {
            fac[i].v=k;
        }
    }
    return cnt;
}
    
int main()
{
    int n,m,i,cnt;
    while(~scanf("%d%d",&n,&m))
    {
        cnt=find_factor(m);
        ll sum=mypow(m,n);
        for(i=0;i<cnt;i++)
        {
            if(fac[i].v==0)
            {
                continue;
            }
            else if(fac[i].v%2==1)
            {
                sum-=mypow(m/fac[i].num,n);
            }
            else
            {
                sum+=mypow(m/fac[i].num,n);
            }
        }
        printf("%lld\n",sum);
    }
    return 0;
}
        



原创粉丝点击