P4446 [AHOI2018初中組]根式化簡 - 數論
阿新 • • 發佈:2021-06-29
題意
\(T\) 次詢問,每次給一個正整數 \(x\),問最大的整數 \(a\) 滿足 \(a^3b=x\),其中 \(b\) 是正整數。
題解
我想了一個 \(O(Tx^{0.25})\) 的根號分治做法,成功被卡常。
這是正解:
有一個奇妙的性質:把 \(x\) 中所有 \(\le x^{0.25}\) 的質因子都去掉,剩下的數要不然是一個完全立方數,要不然其中所有質因子的次數都小於 \(3\)。
證明:假如剩下的部分能被表示成 \(k^3y\) 的形式(\(k,y>1\)),因為已經去掉了所有 \(\le x^{0.25}\) 的質因子,所以 \(k,y>x^{0.25}\),所以 \(k^3y>x\)
所以我們篩出 \((10^{18})^{0.25}\) 以內的所有質數,再預處理 \(1\sim 10^{18}\) 內的所有完全立方數,就能過了。
不會分析時間複雜度。。。感覺挺奇妙的,時間複雜度應該和根號分治做法一樣,但根號分治就是過不了。
程式碼
#include <cstdio> #include <cstring> #include <cctype> #include <unordered_map> #include <cmath> using namespace std; #define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti) #define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti) template<typename T> void Read(T &x){ x=0;int _f=1; char ch=getchar(); while(!isdigit(ch)) _f=(ch=='-'?-1:_f),ch=getchar(); while(isdigit(ch)) x=x*10+(ch^48),ch=getchar(); x=x*_f; } template<typename T,typename... Args> void Read(T &x,Args& ...others){ Read(x);Read(others...); } typedef long long ll; const int Inf=0x3f3f3f3f,Q=31655,CBRT=1e6+5; int prime[Q],prCnt=0,vis[Q]; void Sieve(int mx){ vis[1]=1; For(i,2,mx){ if(!vis[i]) prime[++prCnt]=i; for(int j=1;j<=prCnt&&1LL*i*prime[j]<=mx;++j){ vis[i*prime[j]]=1; if(i%prime[j]==0) break; } } } unordered_map<ll,ll> mp; int T; int main(){ Sieve(Q-1); for(ll i=1;i<CBRT;++i) mp.insert({i*i*i,i}); Read(T); while(T--){ ll x,ans=1;Read(x); for(int j=1;j<=prCnt;++j){ int cnt=0; while(x%prime[j]==0){ ++cnt,x/=prime[j]; if(cnt>=3) ans*=prime[j],cnt-=3; } } if(mp.count(x)) ans*=mp[x]; printf("%lld\n",ans); } return 0; }