Processing math: 100%

最小公倍数之和 题解

转化下题面。

ni=1nj=1lcm(i,j)cnticntj

其中, ncntk(1kn) 已事先给出规模均为 5e4


ni=1nj=1lcm(i,j)cnticntj

=ni=1nj=1ijgcd(i,j)cnticntj

=nd=1ni=1nj=1[gcd(i,j)==d]ijdcnticntj

=nd=1ndi=1ndj=1[gcd(i,j)==1]ijdcntidcntjd

=nd=1ndi=1ndj=1s|gcd(i,j)μ(s)ijdcntidcntjd

=nd=1dndi=1ndj=1s|gcd(i,j)μ(s)ijcntidcntjd

=nd=1dnds=1μ(s)nsdi=1nsdj=1s2ijcntidscntjds

=nd=1dnds=1μ(s)s2nsdi=1nsdj=1ijcntidscntjds

=nd=1dnds=1μ(s)s2nsdi=1icntidsnsdj=1jcntjds

=nd=1dnds=1μ(s)s2(nsdi=1icntids)2

=nsd=1sds|sd(μ(s)s)(nsdi=1icntids)2

sd 换成 一个漂亮点的数 T , 最后的式子就是

nT=1T(s|Tμ(s)s)(nTi=1icntiT)2

中间的括号可以 O(nlogn) 预处理, 后面的括号暴力算的总复杂度是个调和级数, 复杂度也是 O(nlogn)

luogu数据AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 50005;
#define li long long

int prime[maxn], v[maxn], mu[maxn], m;
li f[maxn];
void euler(int n) {
	mu[1] = 1;
	for(int i=2; i<=n; ++i) {
		if(!v[i]) {
			v[prime[++m] = i] = i;
			mu[i] = -1;
		}
		for(int j=1; j<=m; ++j) {
			if(prime[j] > n/i || prime[j] > v[i]) break;
			v[prime[j] * i] = prime[j];
			mu[prime[j] * i] = mu[i] * (i%prime[j] ? -1 : 0);
		}
	}
	for(int i=1; i<=n; ++i)
		for(int j=1; j<=n/i; ++j)
			f[i*j] += i * mu[i];
}

int n, a[maxn], c[maxn];
int N;
int main()
{
	scanf("%d", &n);
	for(int i=1;i<=n;++i) {
		scanf("%d", &a[i]);
		++c[a[i]];
		N = max(N, a[i]);
	}
	euler(N);
	li ans = 0ll;
	for(int T=1; T<=N; ++T) {
		li nowans = 0ll;
		for(int i=1; i<=N/T; ++i) nowans += i*c[i*T];
		nowans = nowans * nowans;
		ans += T * f[T] * nowans;
	}
	cout << ans;
	return 0;
 } 
posted @   xwmwr  阅读(183)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示