Codeforces Round #757 (Div. 2) - D2. Divan and Kostomuksha (hard version)
GCD + DP + 调和级数/埃式筛
[Problem - D - Codeforces](https://codeforces.com/contest/1610/problem/D)
题意
给出一个长度为 的数组
可以重新排列 数组,使得 最大
思路
-
设 为 的倍数有多少个,easy版本可用调和级数,hard版本可 分解因数
-
若 开头,最优策略是把 的倍数全都紧接着放在 之后,他们的贡献为
-
设以 作为 的答案为 (这里并非 开头 就是 , 的任何因数都可以), 把 的倍数 放到 的前面时会更优,因此 转移
-
在 向 转移的过程中,除了 的倍数 个以外的 个数对贡献并没有改变
且是 的倍数但不是 的倍数的数的贡献也没有改变,只有 个数的贡献由 变成了 , 因此转移方程为
-
easy 版本可用调和级数;hard版本考虑优化,其实并非 向它的每个倍数 都需要转移,只需要转移向素数倍的 就行(感受一下,应该也可以证)
类比埃式筛,时间复杂度为
代码
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
typedef long long ll;
typedef pair<int, int> PII;
const int N = 2e7 + 10;
ll f[N];
int n;
ll cnt[N];
int pr[N / 5], p[N];
int t;
void get_primes(int n)
{
p[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!p[i])
{
p[i] = i;
pr[++t] = i;
}
for (int j = 1; j <= t && pr[j] <= n / i; j++)
{
p[i * pr[j]] = pr[j];
if (p[i] == pr[j])
break;
}
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
get_primes(N - 10);
cin >> n;
for (int i = 1, x; i <= n; i++)
{
cin >> x;
for (int j = 1; j <= x / j; j++)
{
if (x % j == 0)
{
cnt[j]++;
if (j != x / j)
cnt[x / j]++;
}
}
}
f[1] = n;
for (int x = 1; x <= N - 10; x++)
{
for (int i = 1; i <= t && pr[i] <= (N - 10) / x; i++)
{
int y = x * pr[i];
f[y] = max(f[y], f[x] + (y - x) * cnt[y]);
}
}
cout << *max_element(f + 1, f + N - 9) << endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!