D. Magic LCM

题意:

给定一个长度为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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值