容斥专辑(2)
1、hdu 2204 Eddy's爱好
知识点:1、容斥原理
2、由 n^(1/p) ,就可以知道在小于等于 n 的数字中,指数为p的有多少个 (其中包括 1^p 这种类型的)
3、10^18 < 2^62
方法:通过观察,可以发现若一个数可以表示成x^(k*t),则可以表示成(x^k)^t。
根据正整数唯一分解定理,正整数都可以写成素数相乘,因此指数必然为素数和素数的乘积。
枚举素数便可以得到指数为p的个数,但是可能出现重复,例如:x^3=y^5,其中x=t^5,y=t^3。
运用容斥原理,设a[i]表示指数为第i个素数的个数,那么答案等于满足一个的,减去两个的,加上三个的……
由于2^60>10^18,2*3*5*7>60,所以只要枚举到三即可。
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<iostream> #define ll long long using namespace std; const int maxn=65; vector <ll> prime; bool p[maxn]; void init() { memset(p,true,sizeof(p)); for(int i=2;i<9;i++) { if(p[i]) { for(int j=i*i;j<maxn;j+=i) p[j]=false; } } prime.clear(); for(int i=2;i<maxn;i++) { if(p[i]) prime.push_back(i); } } int main() { ll n,ans,tmp; init(); while(cin>>n) { ans=0; for(int i=0;i<prime.size();i++) { tmp=pow(n,1.0/prime[i]); if(tmp==1) break; ans+=tmp-1; } for(int i=0;i<prime.size();i++) { for(int j=i+1;j<prime.size();j++) { tmp=pow(n,1.0/(prime[i]*prime[j])); if(tmp==1) break; ans-=tmp-1; } } for(int i=0;i<prime.size();i++) { for(int j=i+1;j<prime.size();j++) { for(int k=j+1;k<prime.size();k++) { tmp=pow(n,1.0/(prime[i]*prime[j]*prime[k])); if(tmp==1) break; ans+=tmp-1; } } } cout<<ans+1<<endl; } return 0; }
你若是天才,我便是疯子