1. 程式人生 > 其它 >P4446 [AHOI2018初中組]根式化簡 - 數論

P4446 [AHOI2018初中組]根式化簡 - 數論

題意

\(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;
}