Codeforces Round #757 (Div. 2) D1

大意:给定长度为 n 的序列 a, 序列中的最大值<=5e6 ,求对于该序列任意排序所得

∑ i n g c d ( a 1 , a 2 . . . a i ) \sum{_i^n gcd(a_1,a_2...a_i)} ingcd(a1,a2...ai)的最大值。

思路:令 f i f_i fi 表示以数字 i 为 开头的 序列 a 的最大值

想想对于 f j f_j fj 怎么从 f i f_i fi 进行转移,我们想到只有当 j 为 i 的倍数是才会使得结果更优,因为如果不是 i 的倍数,那么开始的几个 gcd 是比 i 小的。所以我们状态转移的时候枚举 i 的倍数转移就行了。接下来就是怎么进行计算。我们记 c n t i cnt_i cnti 为 i 的倍数的个数。

因为 j 是 i 的倍数 j>i ,必然有 c n t i > c n t j cnt_i > cnt_j cnti>cntj ,并且我们把所有的 j 都放到开头是优的。因为 j 的个数是比 i 少的,那么用 j 替换开头的 i 时,是不能把 i 全部换掉的,对于原来的 f i f_i fi 后面的 j 受 i 的对结果并没有贡献,把 j 放到前面就能对结果贡献, f j = f i + ( j − i ) c n t j f_j = f_i +(j-i) cnt_j fj=fi+(ji)cntj

代码如下:

#include <bits/stdc++.h>
#define int long long 
#define rep(i,bbb,eee) for(int i=bbb;i<=eee;i++)
#define frep(i,bbb,eee) for(int i=bbb;i>=eee;i--)
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
#define pb push_back
#define AC signed
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const int N=5000010,M=1000000007;
int qmi(int a,int b)
{
	int res=1;
	while(b)
	{
		if(b&1)res=res*a%M;
		a=a*a%M;
		b>>=1;
	}
	return res%M;
}
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)&&ch!='-')ch=getchar();
    if(ch=='-')f=-1,ch=getchar();
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
inline void print(int x)
{   
   if(x<0){putchar('-');x=-x;}
   if(x>9) print(x/10);
   putchar(x%10+'0');
}
//____________________________________________//
int f[N],cnt[N],n,m;
void solve()
{
	cin>>n;
	rep(i,1,n)
	{
		int x;
		cin>>x;
		m=max(m,x);
		cnt[x]++;
	}
	for(int i=1;i<=m;i++)
		for(int j=i*2;j<=m;j+=i)
			cnt[i]+=cnt[j];
	f[1]=n;
	for(int i=1;i<=m;i++)
		for(int j=i*2;j<=m;j+=i)
			f[j]=max(f[j],f[i]+(j-i)*cnt[j]);
	int ans=0;
	for(int i=1;i<=m;i++)ans=max(ans,f[i]);

	cout<<ans<<"\n";

}
AC main()
{
	ios::sync_with_stdio(false);cin.tie(0);
	int _=1;
	//cin>>_;
	while(_--)solve();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值