题意:
给定一个长度为n的数组,可以对数组进行无限次操作,每次操作是选择两个位置i,j,使a[i]=__gcd(a[i],a[j]) a[j]=lcm(a[i],a[j]);现在要求出操作之后,数列的总和最大值,结果可能很大,需要对998244353进行取模
思路:
对于每一次的操作,数的和增加的值>=0(如图),因此对于我们每一个出现的质数,都将最高次幂垒到第一个盒子里,次高次幂垒到第二个盒子里,以此类推,这样形成的数组和一定是最大的
const int N=2e6+10,M=5e2+10;
const int mod=998244353;
int n,m,a[N],st[N],b[N],stst[N],mn[N],mp[N];
void init()//利用线性筛,预处理出每个数的最小质因子
{
int jk=0;
for(int i=2;i<N-5;i++)
{
if(mn[i]==0)
{
mn[i]=i;
stst[++jk]=i;
}
for(int j=1;j<=jk;j++)
{
if(i*stst[j]>=N-5)break;//太大
mn[i*stst[j]]=stst[j];
if(mn[i]==stst[j])break;//可被最小质因子搞出来
}
}
}
int cnt[N][30];
void df()
{
cin>>n;
int o=0;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
while(x>1)
{
int p=mn[x];//当前这个数的最小质因子
int tt=0;
while(x%p==0)
{
tt++;
x/=p;
}
st[p]=max(st[p],tt);//统计最高次幂
cnt[p][tt]++;//当前p^tt出现的次数
mp[p]++;//当前的这个数总共有几个
if(mp[p]==1)
b[++o]=p;
}
a[i]=1;
}
a[0]=1;
// for(int i=1;i<=o;i++)
// {
// cout<<b[i]<<" "<<mp[b[i]]<<" "<<st[b[i]]<<endl;
// }
//因为是公倍数,所以将最大的每一个倍数加到后面的大的数身上
for(int k=1;k<=o;k++)
{
int ii=b[k];
//当前的质数为ii
int w=mp[ii];//当前的这个数上总共有多少的;将最小的放到最后面的盒子里,次小的放在倒数第二个盒子里,以此类推
int jk=1;
for(int i=1;i<=st[ii];i++)
{
jk=jk*(ii)%mod;
for(int j=1;j<=cnt[ii][i];j++)
{
a[w]=a[--w]*jk%mod;//依次放到盒子里
}
cnt[ii][i]=0;
}
st[ii]=0;
mp[ii]=0;
}
// for(int i=0;i<n;i++)cout<<a[i]<<" ";
// cout<<endl;
int res=0;
for(int i=0;i<n;i++)
res=(res+a[i]%mod)%mod;
cout<<res<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie();
cout.tie();
init();
int t=1;
cin>>t;
while(t--)
{
df();
}
return 0;
}