【题解】Luogu-P3911 最小公倍数之和
Description
-
给定整数 和 个整数 ,求
-
对于 的数据,。
Solution
直接反演不行,考虑计算贡献。
设 。
观察到值域(即 ),开一个数组 记录数 的出现次数。
首先 的线性筛是 的。
对于 ,用经典套路枚举倍数 预处理。
直接暴力也是 的。
总时间复杂度为 。还带大常数
Code
// 18 = 9 + 9 = 18.
#include <iostream>
#include <cstdio>
#define Debug(x) cout << #x << "=" << x << endl
#define int long long
using namespace std;
const int MAXN = 5e4 + 5;
const int N = 5e4;
int p[MAXN], mu[MAXN], res[MAXN];
bool vis[MAXN];
void pre()
{
mu[1] = 1;
for (int i = 2; i <= N; i++)
{
if (!vis[i])
{
p[++p[0]] = i;
mu[i] = -1;
}
for (int j = 1; j <= p[0] && i * p[j] <= N; j++)
{
vis[i * p[j]] = true;
if (i % p[j] == 0)
{
mu[i * p[j]] = 0;
break;
}
mu[i * p[j]] = mu[i] * mu[p[j]];
}
}
for (int i = 1; i <= N; i++)
{
for (int j = 1; i * j <= N; j++)
{
res[i * j] += mu[i] * i;
}
}
}
int a[MAXN], c[MAXN];
signed main()
{
pre();
int n, m = 0;
scanf("%lld", &n);
for (int i = 1; i <= n; i++)
{
scanf("%lld", a + i);
m = max(m, a[i]);
c[a[i]]++;
}
int ans = 0;
for (int i = 1; i <= m; i++)
{
int tmp = 0;
for (int j = 1; j <= m / i; j++)
{
tmp += j * c[j * i];
}
ans += i * tmp * tmp * res[i];
}
printf("%lld\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通