HDU - 2204 Eddy’s爱好
题意:
给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数
题解:
参考题解:
我们先举例找找规律
1~10以内2的次方有多少个?有12=1,22=4,32=9,一共三个,10开方(向下取整)为3
也就是1~n之间k次方数有多少个 ,等于n(1/k),这算是个结论其实
如果我们直接按这个计算,会发现有很多重复,比如有个数是2的次方,也有可能是4的次方,也有可能是6的次方,但是这些其实在2的次方中就已经计算了,而4,8是2的倍数,所以我们只需要管素数次方就行了,一个2就涵盖了所有4,6,8等等。你也可以这么理解:如果M(ab)也可以写成(Ma)b,如果指数不是质数,那么一定可以每另外一组数字表示,且这组数字的指数是质数。所以说我们只需要统计指数是质数的数字能够组成多少个n以内的数字。
那是不是这样就没有重复了?也不是,不同数之间有可能也有,就比如一个数是6的次方,他就被素数2次方和素数3次方同时给统计了,这个要用到容斥,比如272和93会重复是因为他们都能凑出指数6,所以我们需要减去指数6所得到的个数
举个例子:
n=729
指数为2:22,32,42,52,62…272
指数为3:23,33,43,53,63…93
82=26和43=26就是重复的,我们用n计算出指数为6的个数,729(1/6)=1,那么答案就是先+指数为2的,再+指数为3的,最后减指数为6的,这是容斥为2的情况
如果重复的是2,3,5的共同倍数30,同理+2+3+5- 2 * 3 -3 * 5 - 2 * 5 + 2 * 3 * 5(结合下图应该能明白),这是容斥的层数为3的情况
那容斥为4的情况呢?题目说了n在1e18的范围内,说明mk,k取值要小于61,而2 * 3 * 5<61<2 * 3 * 5 * 7,所以容斥四层的情况不用考虑,
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
typedef long long ll;
using namespace std;inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
int p[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61};
int main()
{ll n;while(cin>>n){ll ans=1;ll tmp;for(int i=0;;i++){tmp=(ll)pow(n,1.0/p[i]);if(tmp<2)break;//说明n开p[i]次方不足 ans+=tmp-1;for(int j=i+1;;j++){tmp=(ll)pow(n,1.0/p[i]/p[j]);if(tmp<2)break;ans-=tmp-1;for(int k=j+1;;k++){tmp=(ll)pow(n,1.0/p[i]/p[j]/p[k]);if(tmp<2)break;ans+=tmp-1;} } }cout<<ans<<endl;}return 0;
}