【题解】Luogu-P3911 最小公倍数之和

P3911 最小公倍数之和

Description

  • 给定整数 nn 个整数 a1,a2,,an,求

    i=1nj=1nlcm(ai,aj)

  • 对于 100% 的数据,1n,ai5×104

Solution

直接反演不行,考虑计算贡献。

max{a1,a2,,an}=m

观察到值域(即 m5×104,开一个数组 ci 记录数 i 的出现次数。

i=1nj=1nlcm(ai,aj)=i=1mj=1mlcm(i,j)cicj=i=1mj=1mijgcd(i,j)cicj=i=1mj=1md=1mijd[gcd(i,j)=d]cicj=d=1mi=1mdj=1md(id)(jd)d[gcd(i,j)=1]cidcjd=d=1mi=1mdj=1mdijdcidcjdkgcd(i,j)μ(k)=d=1mdk=1mdμ(k)i=1md[ki]icidj=1md[kj]jcjd=d=1mdk=1mdμ(k)(i=1mdkikcidk)2=d=1mdk=1mdμ(k)k2(i=1mTiciT)2=T=1m(i=1mTiciT)2kTμ(k)k2(Tk)=T=1mT(i=1mTiciT)2kTμ(k)k=T=1mT(i=1mTiciT)2kTμ(k)k

首先 μ 的线性筛是 O(m) 的。

对于 kTμ(k)k,用经典套路枚举倍数 Θ(m1+m2+m3+)=Θ(mlnm) 预处理。

T=1mT(i=1mTiciT)2 直接暴力也是 Θ(mlnm) 的。

总时间复杂度为 Θ(mlnm)还带大常数

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;
}
posted @   mango09  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
-->
点击右上角即可分享
微信分享提示