HDU-2204- Eddy’s爱好 (容斥原理)
题意
给出一个数n,问1-n中有多少个数可以表示为m^k,m,k均为正整数且k>1
(1<=n<=1^18)
题解
(一开始^以为是异或懵逼了好久....)
额,显然1这个数比较讨厌1的多少次方都得1,对答案的贡献为1,最后加上就可以了。
然后,我们发现x^4=(x^2)^2四次方可以用平方的平方代替,我们只枚举质数次方,然后用n(1/x)等于x次方在n之内的数的个数(这个东西会有精度问题)。
就可以求出质数次方在1到n之内的数有多少。但是,发现(x^2)^3==(x^3)^2,(x^2)^3(或者说(x^3)^2)被算了两次。
这时,就用到容斥原理了。因为2^60>1e18所以质数次方考虑到59,又因为2*3*5*7=210>60,所以容斥时容斥到三个数就行了。
(容斥原理居然是小学奥数4大定理之一)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 long long prime[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59}; 8 long long n,ans; 9 void dfs(long long now,long long num,long long res,long long k){ 10 if(res==0){ 11 long long tmp=pow(n,1.0/num); 12 if(pow(tmp,(double)num)>n) tmp--; 13 tmp--; 14 if(tmp>0){ 15 if(k&1)ans+=tmp; 16 else ans-=tmp; 17 } 18 return; 19 } 20 if(now>17)return; 21 if(num*prime[now]<60)dfs(now+1,num*prime[now],res-1,k); 22 dfs(now+1,num,res,k); 23 } 24 int main(){ 25 while(scanf("%lld",&n)!=EOF){ 26 ans=0; 27 for(long long i=1;i<=3;i++)dfs(1,1,i,i); 28 printf("%lld\n",ans+1); 29 } 30 return 0; 31 }