【MOBAN】Codeforces Round #757 (Div. 2) D2狄利克雷前缀和
又是罚坐的一天,不过学习(fuxi)到了一个新东西---狄利克雷前缀和。
我们发现最后gcd的前缀列是单调递减的。然后发现前一项是后一项的倍数,且满足后一项放的数恰不会被前一项放的数整除。我们设dp[i]表示当前列放在最前面的gcd是i时的gcd总和最大值,然后转移就可以了。思考后发现满足后一项一定是后一项乘质数最优(当然如果像100,1中间没有质数,中间100,50,10看做cnt==0就可以了)。所以发现有一种叫狄利克雷前缀和的东西。code it...
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 2e7;
int n;
int ct[M + 5], pri[M], cnt;
ll f[M + 5];
bool nop[M + 5];
void eula() {
for (int i = 2; i <= M; i++) {
if (!nop[i])
pri[++cnt] = i;
for (int j = 1; j <= cnt && 1ll * pri[j] * i <= M; j++) {
nop[i * pri[j]] = 1;
if (i % pri[j] == 0)
break;
}
}
}
int main() {
eula();
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
ct[x]++;
}
for (int i = 1; i <= cnt; i++) { // dilichlet后缀和
for (int j = M / pri[i]; j >= 1; j--) {
ct[j] += ct[j * pri[i]];
}
}
f[1] = ct[1];
ll ans = 0;
for (int i = 1; i <= M; i++) {
for (int j = 1; j <= cnt && 1ll * i * pri[j] <= M; j++) {
int x = i * pri[j];
f[x] = max(f[x], 1ll * ct[x] * (x - i) + f[i]);
}
ans = max(ans, f[i]);
}
printf("%lld", ans);
return 0;
}