大意:给定长度为 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+(j−i)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;
}