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(T∗n∗m)。此时我们统计出了所有质因子的最高次幂,欧拉筛打一个 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(T∗m/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;
}