1. 程式人生 > >2204 Eddy's愛好 容斥

2204 Eddy's愛好 容斥

Ignatius 喜歡收集蝴蝶標本和郵票,但是Eddy的愛好很特別,他對數字比較感興趣,他曾經一度沉迷於素數,而現在他對於一些新的特殊數比較有興趣。 這些特殊數是這樣的:這些數都能表示成M^K,M和K是正整數且K>1。 正當他再度沉迷的時候,他發現不知道什麼時候才能知道這樣的數字的數量,因此他又求助於你這位聰明的程式設計師,請你幫他用程式解決這個問題。 為了簡化,問題是這樣的:給你一個正整數N,確定在1到N之間有多少個可以表示成M^K(K>1)的數。

Input

本題有多組測試資料,每組包含一個整數N,1<=N<=1000000000000000000(10^18).

Output

對於每組輸入,請輸出在在1到N之間形式如M^K的數的總數。 每組輸出佔一行。

Sample Input

10
36
1000000000000000000

Sample Output

4
9
1001003332

題解:很明顯要用容斥去做,但1e18最多可以開64次方,64以內的素數有18個,但是2*3*5=30 所以容斥3層即可

1次方是不能算的 所以計算的時候都要減1  但是1可以寫成1的任意次方 所以結果加1

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=12;
typedef long long ll;
ll n,m,a[N];
int prime[70];
int ok[50],len;
void init()
{
    prime[1]=1;
    for(int i=2;i<=64;i++)
    {
        if(!prime[i])
        {
            ok[len++]=i;
            for(int j=i+i;j<=64;j+=i)
                prime[j]=1;
        }
    }
}
int main()
{
    init();
    while(scanf("%lld",&n)!=EOF)
    {
        ll ans=0;
        for(int i=0;i<len;i++)
        {
            int tmp=pow(n,1.0/ok[i]);
            ans+=tmp-1;
            for(int j=i+1;j<len;j++)
            {
                tmp=pow(n,1.0/ok[i]/ok[j]);
                ans-=tmp-1;
                for(int k=j+1;k<len;k++)
                {
                    tmp=pow(n,1.0/ok[i]/ok[j]/ok[k]);
                    ans+=tmp-1;
                }
            }
        }
        cout<<ans+1<<endl;
    }
	return 0;
}