背景
A
H
O
I
AHOI
AHOI竟然有初中组的良心设置,专门即将在初中退役的我找回了一点自信。
题目传送门:
https://www.luogu.org/problemnew/show/P4446
题意:
求正整数
a
,
b
a,b
a,b,使其满足
a
3
∗
b
=
n
a^3*b=n
a3∗b=n的最大的
a
a
a。
思路 & \& &代码:
考虑纯暴力。
#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);
}
}
轻松
60
60
60分。
考虑优化。
发现我们只用枚举质数作为
a
a
a即可,由唯一分解定理可知任意的合数
a
a
a都能分为若干个质数的乘积,最后再相乘即可。
#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);
}
}
轻松
80
80
80分。
再考虑优化。
时间复杂度已是
Θ
(
T
∗
k
)
\Theta(T*k)
Θ(T∗k),其中
k
k
k是一个大常数。
不妨考虑缩小
k
k
k的值,发现最后的数可能比较大,可以用二分来实现最后求做完后的
n
n
n是否是
3
3
3次方数。
发现
5000
0
3
=
1.25
∗
1
0
14
50000^3=1.25*10^{14}
500003=1.25∗1014,略小于
1
0
18
10^{18}
1018,但因为后面有一个二分判断(相当于再乘上一个
50000
50000
50000,从而超过
1
0
18
10^{18}
1018),已经不影响结果。因此正确性可以证明。
#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));
}
}