【SSLOJ】HR的疑惑
阿新 • • 發佈:2020-08-11
題目
求 \([1,n]\) 中有多少個數能寫作 \(a^b(b>1\) 且 \(a,b\) 均為正整數 \()\)。
\(n\leq 10^{18}\)。
思路
容易發現,只有當一個數字 \(k\) 被表示成 \(a^b\),且 \(a=a'^{b'}\) 時才會計算重複。所以考慮如何對任意一個數 \(k\) 只計算 \(b\) 最小的方案。
為了防止 \(b\) 被拆分成 \(a'^{b'}\),只列舉 \([1,64]\) 中的質數作為指數即可。
發現當 \(b=2\) 時,任意 \(a^b\) 都不會計算重複,所以直接將不超過 \(n^{\frac{1}{2}}\) 的數字記錄貢獻。
對於 \(b>2\)
用一個 \(\operatorname{STL::map}\) 記錄每個數字是否計算過貢獻即可。注意要特判指數為 2 的情況。
時間複雜度 \(O(n^{\frac{1}{3}}\log n)\)。\(\operatorname{STL::map}\) 的時間忽略不計 (bushi。
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int LG=65,M=18; const int prm[20]={0,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61}; ll n,ans; map<ll,bool> vis; int main() { scanf("%lld",&n); ans=pow(n,0.5); for (register int i=1;i<=M;i++) { int Maxn=pow(n,1.0/prm[i]); for (register int j=2;j<=Maxn;j++) { ll p=pow(j,0.5),q=pow(j,prm[i]); if (p*p==j || vis[q]) continue; vis[q]=1; ans++; } } printf("%lld",ans); return 0; }