给定(A_1,A_2,dots,A_N),求(sum_{i=1}^Nsum_{j=1}^Nlcm(A_i,A_j))
(1le Nle 50000;1le A_ile 50000)
为了推式子方便我们设:
(n=50000) (a_i=sum_{j=1}^N[A_j=i])
答案就是(sum_{i=1}^nsum_{j=1}^na_ia_jlcm(i,j))
(sum_{i=1}^nsum_{j=1}^na_ia_jlcm(i,j))
(=sum_{i=1}^nsum_{j=1}^na_ia_jfrac{ij}{gcd(i,j)})
(=sum_{p=1}^nfrac1psum_{i=1}^nsum_{j=1}^na_ia_jij[gcd(i,j)=p])
(=sum_{p=1}^npsum_{i=1}^{n/p}sum_{j=1}^{n/p}a_{ip}a_{jp}ij[gcd(i,j)=1])
(=sum_{p=1}^npsum_{i=1}^{n/p}sum_{j=1}^{n/p}a_{ip}a_{jp}ijsum_{d|i,d|j}mu(d))
(=sum_{p=1}^npsum_{d=1}^nmu(d)d^2sum_{i=1}^{n/dp}sum_{j=1}^{n/dp}a_{idp}a_{jdp}ij)
(=sum_{q=1}^nqsum_{d|q}dmu(d)sum_{i=1}^{n/q}sum_{j=1}^{n/q}a_{iq}a_{jq}ij)
(=sum_{q=1}^nqsum_{d|q}dmu(d)left(sum_{i=1}^{n/q}a_{iq}i ight)^2)
(sum_{i=1}^{n/q}a_{iq}i)对于每个(q)求值,总复杂度为(frac n 1+frac n 2+frac n 3+dots+frac nn)复杂度为调和级数(O(nlog n))
前半部分筛(d)后枚举(d)及其倍数,复杂度还是调和级数(O(nlog n))
然后直接求和就行了,貌似不用打数论分块
41行一遍A。。。真不用打数论分块,复杂度nlogn
#include <cstdio>
using namespace std;
int prime[50010], mu[50010], tot, fuck = 50000;
bool vis[50010];
long long sum1[50010], sum2[50010];
int bucket[50010];
int main()
{
mu[1] = 1;
for (int i = 2; i <= fuck; i++)
{
if (vis[i] == false) prime[++tot] = i, mu[i] = -1;
for (int j = 1; j <= tot && i * prime[j] <= fuck; j++)
{
vis[i * prime[j]] = true;
if (i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
mu[i] *= i;
}
for (int d = 1; d <= fuck; d++)
for (int q = d; q <= fuck; q += d)
sum1[q] += mu[d];
for (int i = 1; i <= fuck; i++)
sum1[i] *= i;
int n; scanf("%d", &n);
for (int x, i = 1; i <= n; i++)
scanf("%d", &x), bucket[x]++;
long long ans = 0;
for (int q = 1; q <= fuck; q++)
{
int sb = fuck / q;
for (int i = 1; i <= sb; i++)
sum2[q] += bucket[i * q] * (long long)i;
ans += sum2[q] * sum1[q] * sum2[q];
}
printf("%lld
", ans);
return 0;
}