luogu P4446 [AHOI2018初中組]根式化簡
阿新 • • 發佈:2018-12-15
背景
竟然有初中組的良心設定,專門即將在初中退役的我找回了一點自信。
題目傳送門:
https://www.luogu.org/problemnew/show/P4446
題意:
求正整數
,使其滿足
的最大的
。
思路 程式碼:
考慮純暴力。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;
LL n;
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld",&n);
LL ans=1,p=sqrt(n);
for(LL i=2;i<=p;i++)
{
int tot=0;
while(!(n%i)) n/=i,tot++;
if(tot>=3) ans*=pow(i,(int)(tot/3));
if(n==1) break;
}
printf("%lld\n",ans);
}
}
輕鬆
分。
考慮優化。
發現我們只用列舉質數作為
即可,由唯一分解定理可知任意的合數
都能分為若干個質數的乘積,最後再相乘即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;
LL n;
int t=0;
int prime[1000010];
bool bz[1000010];
void init(int ma)
{
bz[0]=bz[1]=true;
for(int i=2;i<=ma;i++)
{
if(!bz[i]) prime[++t]=i;
for(int j=1;j<=t&&i*prime[j]<=ma;j++)
{
bz[i*prime[j]]=true;
if(!(i%prime[j])) break;
}
}
}
int main()
{
int T;
scanf("%d",&T);
init(1000000);
while(T--)
{
LL ans=1;
scanf("%lld",&n);
for(int i=1;i<=t;i++)
{
int tot=0;
if((LL)prime[i]*prime[i]*prime[i]>n) break;
while(!(n%prime[i])) n/=prime[i],tot++;
ans*=pow(prime[i],(int)tot/3);
}
printf("%lld\n",ans);
}
}
輕鬆
分。
再考慮優化。
時間複雜度已是
,其中
是一個大常數。
不妨考慮縮小
的值,發現最後的數可能比較大,可以用二分來實現最後求做完後的
是否是
次方數。
發現
,略小於
,但因為後面有一個二分判斷(相當於再乘上一個
,從而超過
),已經不影響結果。因此正確性可以證明。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
using namespace std;
LL n;
int t=0;
int prime[50010];
bool bz[50010];
void init(int ma)
{
bz[0]=bz[1]=true;
for(int i=2;i<=ma;i++)
{
if(!bz[i]) prime[++t]=i;
for(int j=1;j<=t&&i*prime[j]<=ma;j++)
{
bz[i*prime[j]]=true;
if(!(i%prime[j])) break;
}
}
}
LL check(LL x)
{
LL l=1,r=1000000,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(mid*mid*mid==x) return mid;
if(mid*mid*mid<x) l=mid+1; else r=mid-1;
}
if(l*l*l==x) return l;
return false;
}
int main()
{
int T;
scanf("%d",&T);
init(50000);
while(T--)
{
LL ans=1;
scanf("%lld",&n);
for(int i=1;i<=t;i++)
{
int tot=0;
if((LL)prime[i]*prime[i]*prime[i]>n) break;
while(!(n%prime[i])) n/=prime[i],tot++;
ans*=pow(prime[i],(int)tot/3);
}
LL o=check(n);
printf("%lld\n",ans*(!o?1:o));
}
}