容斥专辑(2)

1、hdu 2204  Eddy's爱好 

 知识点:1、容斥原理

            2、由 n^(1/p) ,就可以知道在小于等于 n 的数字中,指数为p的有多少个 (其中包括 1^p 这种类型的)

            3、10^18 < 2^62

 方法:通过观察,可以发现若一个数可以表示成x^(k*t),则可以表示成(x^k)^t。

         根据正整数唯一分解定理,正整数都可以写成素数相乘,因此指数必然为素数和素数的乘积。

         枚举素数便可以得到指数为p的个数,但是可能出现重复,例如:x^3=y^5,其中x=t^5,y=t^3。

         运用容斥原理,设a[i]表示指数为第i个素数的个数,那么答案等于满足一个的,减去两个的,加上三个的……

         由于2^60>10^18,2*3*5*7>60,所以只要枚举到三即可。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<iostream>
#define ll long long
using namespace std;

const int maxn=65;
vector <ll> prime;
bool p[maxn];

void init()
{
    memset(p,true,sizeof(p));
    for(int i=2;i<9;i++)
    {
        if(p[i])
        {
            for(int j=i*i;j<maxn;j+=i)
            p[j]=false;
        }
    }
    prime.clear();
    for(int i=2;i<maxn;i++)
    {
        if(p[i])
        prime.push_back(i);
    }
}

int main()
{
    ll n,ans,tmp;
    init();
    while(cin>>n)
    {
        ans=0;
        for(int i=0;i<prime.size();i++)
        {
            tmp=pow(n,1.0/prime[i]);
            if(tmp==1) break;
            ans+=tmp-1;
        }
        for(int i=0;i<prime.size();i++)
        {
            for(int j=i+1;j<prime.size();j++)
            {
                tmp=pow(n,1.0/(prime[i]*prime[j]));
                if(tmp==1) break;
                ans-=tmp-1;
            }
        }
        for(int i=0;i<prime.size();i++)
        {
            for(int j=i+1;j<prime.size();j++)
            {
                for(int k=j+1;k<prime.size();k++)
                {
                    tmp=pow(n,1.0/(prime[i]*prime[j]*prime[k]));
                    if(tmp==1) break;
                    ans+=tmp-1;
                }
            }
        }
        cout<<ans+1<<endl;
    }
    return 0;
}

 

posted @ 2016-11-11 15:50  邻家那小孩儿  阅读(137)  评论(0编辑  收藏  举报