【MOBAN】Codeforces Round #757 (Div. 2) D2狄利克雷前缀和

又是罚坐的一天,不过学习(fuxi)到了一个新东西---狄利克雷前缀和。

题目

前缀和资料1

资料2

dls的题解

我们发现最后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;
}
posted @ 2021-11-27 09:54  Newuser233  阅读(52)  评论(0编辑  收藏  举报