多校 HDU6623(数学,二分)

1 篇文章 0 订阅
1 篇文章 0 订阅

努力的抄了某板子,结果居然是一道暴力思维题

Q:
找一个数n(n≤10^{^{18}}^{} )的最小质因子次方数
即对n=p_1^{e_1 } p_2^{e_2 }...p_n^{e_n}找min⁡(e_i)

A:
假如对于n存在p_i≤4000,O(n)筛素数,O(logn)求出p_i≤4000时的e_i min,把n中这样的p_i筛掉(除掉),假如这个时候n已经为1了,说明后面已经没有质因子了,直接输出此时的e_i min

注意:下方提到的n都是筛掉4000以内的素数以后的n。


假如对于n存在p_i≥4000,显然有e_i≤4
即对一个数n,最多有4个≥4000的质因子(两两间可重复)
例如:
存在4个质因子时,有可能e_i=(4),e_i=(3,1),e_i=(2,2),e_i=(2,1,1),e_i=(1,1,1,1)
存在3个质因子略
存在2个质因子略
存在1个质因子略

很显然,只要存在为一个质因子指数为1,min=1,我们姑且把ans赋值为1;
而没有1的情况只有以下几种:(2,2) (4) (3) (2)
除了第一种(2,2)以外,其余都只有一个质因子。
假如这样的单个质因子存在,那么一定有p_i^{e_i}=n
假如是(2,2),这个时候一定存在一个合数
x=p_{i1}*p_{i2}
x^{2}=n
以上,我们发现不管是单个质因子,还是(2,2),都是假如可开i次方,有e=i

次方数i从min⁡(4 ,p_i≤4000时的 min⁡(e_i )  )到2,
我们需要找一下在1到1e9间是否存在一个整数,它的i次方恰等于n,假如存在,ans更改为i,跳出循环(使用二分找)
/*
为什么要从大遍历到小 or 为什么一旦存在就要跳出循环呢:
比方说我们现在的n是由4个4001组成的
(n=4001^{}4)
我们也能找到一个整数的2次方是n
(n=(4001*4001)^{2})
显然这个时候的整数是个合数
*/
这个时候的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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值