http://acm.hdu.edu.cn/showproblem.php?pid=2204
题:
给一个n,问1到n里有多少个数可以表示成成M^K(K>1)的数。
n<=1e18
那么对于一个素因子p
将n开p次方,得到的就是 x^p的数的个数,
同理对p1,p2,做同样操作,但是指数的p1,p2需要容斥一下
然而显然 最小的质数 2 * 3 * 5 * 7>60
而2^60>1e18
因此 对于满足条件的指数,拆成单个质数之后不会超过3个,容斥一下即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const ll p =1000000007;
const int N=100000;
int prim[60];
int ok=0;
bool is_prime(int x)
{
for (int i=2;i<x;i++)
if (x%i==0)return false;
return true;
}
int main()
{
for (int i=2;i<=60;i++)
{
if (is_prime(i))
prim[++ok]=i;//,printf("%d ",i);
}
ll n;
while(scanf("%lld",&n)!=EOF)
{
ll tmp,ans=0;
for (int i=1;i<=ok;i++)
{
tmp=pow((long double)n ,(long double) 1.0/prim[i]);
if (pow((double)tmp,prim[i])>n) tmp--;
tmp--; // k>1
if (tmp>0) ans+=tmp;
}
for (int i=1;i<=ok;i++)
for (int j=i+1;j<=ok;j++)
{
ll tmp_num=prim[i]*prim[j];
if (tmp_num>=60) continue;
tmp=pow((long double)n , (long double)1.0/tmp_num) ;
if (pow((double)tmp,tmp_num)>n) tmp--;
tmp--; // k>1
if (tmp>0) ans-=tmp;
}
for (int i=1;i<=ok;i++)
for (int j=i+1;j<=ok;j++)
for (int k=j+1;k<=ok;k++)
{
ll tmp_num=prim[i]*prim[j]*prim[k];
if (tmp_num>=60) continue;
tmp=pow((long double)n , (long double)1.0/tmp_num);
if (pow((double)tmp,tmp_num)>n) tmp--;
tmp--; // k>1
if (tmp>0) ans+=tmp;
}
printf("%lld\n",ans+1);
}
return 0;
}