HDU2204 Eddy's爱好(容斥原理)
题目问[1,n]有几个数是$m^k (k>1)$形式。
如果这样考虑,m已知k未知,对于每一个m统计其k的数量即$\lfloor log_mn \rfloor$个,再容斥,然而m太多了,完全不可行。
而k远远比m还少,应该反过来考虑,m未知k已知,对于每一个k统计其m的数量,即$\lfloor \sqrt[k]n \rfloor$个。
由于$n \leqslant 10^{18}$,而$2^{60} > 10^{18}$,所以k的范围就是小于60的整数。
然而60用容斥$2^{60}$还是不可行,而$m^{a \times b}$,已知就被$m^a$和$m^b$计数过了,所以对于所有60以内的合数完全可以在一开始就除去,即只考虑60以内的质数。
而60以内的质数只有17个,那么就OK了。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 using namespace std; 5 int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61}; 6 int main(){ 7 long long n; 8 while(~scanf("%lld",&n)){ 9 int pn=0; 10 while((1LL<<prime[pn+1])<=n) ++pn; 11 long long res=0; 12 for(int i=1; i<(1<<pn); ++i){ 13 long long tmp=1; int cnt=0; 14 for(int j=0; j<pn; ++j){ 15 if(((i>>j)&1)==0) continue; 16 tmp*=prime[j]; ++cnt; 17 } 18 if(cnt&1) res+=(long long)(pow(n,1.0/tmp)+1e-8); 19 else res-=(long long)(pow(n,1.0/tmp)+1e-8); 20 } 21 printf("%lld\n",res+1); 22 } 23 return 0; 24 }