努力的抄了某板子,结果居然是一道暴力思维题
Q:
找一个数n(n≤ )的最小质因子次方数
即对...
找min(
)
A:
假如对于n存在≤4000,O(n)筛素数,O(logn)求出
≤4000时的
min,把n中这样的
筛掉(除掉),假如这个时候n已经为1了,说明后面已经没有质因子了,直接输出此时的
min
注意:下方提到的n都是筛掉4000以内的素数以后的n。
假如对于n存在≥4000,显然有
≤4
即对一个数n,最多有4个≥4000的质因子(两两间可重复)
例如:
存在4个质因子时,有可能=(4),
=(3,1),
=(2,2),
=(2,1,1),
=(1,1,1,1)
存在3个质因子略
存在2个质因子略
存在1个质因子略
很显然,只要存在为一个质因子指数为1,min=1,我们姑且把ans赋值为1;
而没有1的情况只有以下几种:(2,2) (4) (3) (2)
除了第一种(2,2)以外,其余都只有一个质因子。
假如这样的单个质因子存在,那么一定有;
假如是(2,2),这个时候一定存在一个合数
以上,我们发现不管是单个质因子,还是(2,2),都是假如可开i次方,有e=i
次方数i从min(4 ,≤4000时的 min(
) )到2,
我们需要找一下在1到1e9间是否存在一个整数,它的i次方恰等于n,假如存在,ans更改为i,跳出循环(使用二分找)
/*
为什么要从大遍历到小 or 为什么一旦存在就要跳出循环呢:
比方说我们现在的n是由4个4001组成的
()
我们也能找到一个整数的2次方是n
()
显然这个时候的整数是个合数
*/
这个时候的ans就是答案了
ac代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int prime[4005];
ll n;
ll rr[5];
void get_prime()
{
for(int i=2;i<=4000;i++)
{
if(prime[i]==0) prime[++prime[0]]=i;
for(int j=1;j<=prime[0]&&prime[j]<=4000/i;j++)
{
prime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
ll quick_pow(ll x,int a)
{
ll ans=1;
while(a)
{
if(a&1)
{
ans=ans*x;
}
x*=x;
a>>=1;
}
return ans;
}
ll fm(int x)
{
ll l=1,r=1e9;
while(l<=r)
{
ll m=(l+r)/2;
ll tt=1;
bool flag=false;
for(int i=1;i<=x;i++)
{
if(tt>1000000000000000000LL/m)
{
flag=true;
break;
}
else tt*=m;
}
if(flag)
{
r=m-1;
}
else l=m+1;
}
return r;
}
bool check(int x)
{
ll l=2,r=rr[x];
while(l<=r)
{
ll m=(l+r)/2;
if(quick_pow(m,x)<=n)
l=m+1;
else
r=m-1;
}
return quick_pow(r,x)==n;
}
int main()
{
get_prime();
for(int i=2;i<=4;i++)
{
rr[i]=fm(i);
}
int t;
scanf("%d",&t);
while(t--)
{
//ll n;
scanf("%lld",&n);
int ans=100;
for(int i=1;i<=prime[0]&&prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
int cnt=0;
while(n%prime[i]==0)
{
cnt++;
n/=prime[i];
}
ans=min(ans,cnt);
}
}
if(n==1LL)
{
printf("%d\n",ans);
}
else
{
int anst=ans;
ans=1;
for(int i=min(4,anst);i>=2;i--)
{
if(check(i))
{
ans=i;
break;
}
}
printf("%d\n",ans);
}
}
return 0;
}