cf1165 Round #560 Div3-D【欧拉筛+快速幂+约数个数】

该博客主要探讨了一道数学与算法相结合的问题,涉及数论和质因数分解。给定一个数列,包含某个数x的所有非1非自身的约数,目标是找出可能的x值或者输出-1表示无法确定。博主通过分析得出,x的约数个数减2应当等于数列的长度,并提出了通过欧拉筛和质因子分解的方法来寻找x。在代码实现中,博主使用了质数表、高精度快速幂运算以及试除法,通过判断累乘结果是否等于数列最大值来确定x。
摘要由CSDN通过智能技术生成

Date:2022.01.05

题意:给定一串数,这串数包含除了1和x本身外x的所有约数,求能不能得出一个x,或得不出一个x(输出-1)。

T=25,n=300,m= 1 0 6 10^6 106

思路①:
首先,x什么时候不存在?
题目说明是除了1和x的所有约数,因此个数一定是x的约数个数-2,因此得到x的所有质因子后,即求出x的约数个数即可判断x是否正确,而x的所有质因子一定在其所有约数中,因此可行。
其次,x怎么得出?
毫无疑问,x是所有数的倍数,因此x一定是所有数的所有质因子的最高次幂的倍数,由此便能对每个数分解质因子,求出所有数中每个质因子的最高次幂,试除法筛一遍质因子, O ( T ∗ n ∗ m O(T*n*\sqrt{m} O(Tnm )。此时我们统计出了所有质因子的最高次幂,欧拉筛打一个 m = 1 0 6 m=10^6 m=106以内的质数表(根据质数定理,质数约等于 m / l n m m/lnm m/lnm不超过 1 0 5 10^5 105个,因此结合t不超过 O ( T ∗ m / l n m ) O(T*m/lnm) O(Tm/lnm)),用于累乘每一个质因子的最高次幂。但是累乘完得出的不一定是x(因为数列中的最大元素可能等于当前 p i a i p_i^{a_i} piai的累乘结果,因此不是x),那此时怎么办?要让x最小,因此一定乘的是最小的那个质因子,这样得出的一定是x!因此,我们只需要判断累乘结果是否为数列中最大元素,若是,则再乘一个最小质因子后变为x;若不是,则累乘结果一定是x。有点啰嗦,看代码吧。
代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
const int N = 1e6+10;
typedef unsigned long long LL;
LL a[N];
LL t,n,m;
LL cnt,prime[N];
bool st[N];
void init(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!st[i]) prime[cnt++]=i;
        for(int j=0;prime[j]<=n/i;j++)
        {
            st[prime[j]*i]=true;
            if(i%prime[j]==0) break;
        }
    }
}
LL qmi(LL a,LL k)
{
    LL res=1;
    while(k)
    {
        if(k&1) res*=a; 
        a=a*a;k>>=1;
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    init(N-1);
    cin>>t;
    while(t--)
    {
        map<LL,LL>q;
        cin>>n;LL maxx=-1e18;
        for(int i=1;i<=n;i++) 
        {
            cin>>a[i];maxx=max(a[i],maxx);
            int m=a[i];
            for(int j=2;j<=m/j;j++)
            {
                if(m%j==0)
                {
                    LL s=0;
                    while(m%j==0) {s++;m/=j;}
                    q[j]=max(q[j],s);
                }
            }
            if(m>1) q[m]=max(q[m],(LL)1);
        }
        LL res=1,ans=1;//res:累乘结果 ans:所求约数个数
        bool flag=true;LL xx=0;
        for(int i=0;i<cnt;i++)
        {
            if(q[prime[i]]>0)
            {
                if(!flag)//这里简化了,最小质因子先不乘进去,先判断累乘完是不是x
                    ans=ans*(q[prime[i]]+1);
                if(flag)
                {xx=prime[i];flag=false;}
                res=res*qmi(prime[i],q[prime[i]]);
            }
        }
        if(maxx<res)
        {
            ans=ans*(q[xx]+1);//累乘结果即为x,只乘一个最小质因子即可
            if(n!=ans-2) {cout<<-1<<endl;continue;}
            cout<<res<<endl;
        }
        else 
        {
            ans=ans*(q[xx]+2);//累乘结果在数列中,多乘一个最小质因子
            if(n!=ans-2) {cout<<-1<<endl;continue;}
            cout<<res*xx<<endl;
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值