1. 程式人生 > >[BZOJ2226][Spoj 5971] LCMSum(莫比烏斯反演)

[BZOJ2226][Spoj 5971] LCMSum(莫比烏斯反演)

題目描述

傳送門

題解

畫一波柿子

i=1n[i,j]
=i=1nni(i,j)
=ni=1nd=1n[(i,n)=d]id
i=id
=nd|ni=1nd[(i,nd)=1]i
利用反演公式[n=1]=d|nμ(d)
=nd|ni=1ndit|(i,nd)μ(t)
=nd|nt|ndi=1nd[t|i]iμ(t)
s(n)=i=1ni=i(i+1)2
nd|nt|nds(ndt)tμ(t)
f(n)=d|ns(nd)tμ(t)
=nd|nf(nd)
F(n)=d|nf(nd)
那麼答案就是nF(n)了嘛…
可以發現f
F都可以用埃式篩法篩出來
那麼詢問就是O(1)的啦…
時間複雜度O(nloglogn+T)

需要注意的是,這個公式:(i,j)=d>(id,jd)=1條件是d|id|j

程式碼

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 1000005
#define LL long long

int T,n;
LL ans;
int p[N],prime[N],mu[N];
LL f[N],F[N];

void
get(int n) { mu[1]=1; for (int i=2;i<=n;++i) { if (!p[i]) { prime[++prime[0]]=i; mu[i]=-1; } for (int j=1;j<=prime[0]&&i*prime[j]<=n;++j) { p[i*prime[j]]=1; if (i%prime[j]==0) { mu[i*prime[j]]=0
; break; } else mu[i*prime[j]]=-mu[i]; } } for (int i=1;i<=n;++i) for (int j=i;j<=n;j+=i) f[j]+=(LL)mu[i]*i*(j/i)*(j/i+1)/2; for (int i=1;i<=n;++i) for (int j=i;j<=n;j+=i) F[j]+=f[j/i]; } int main() { get(1000000); scanf("%d",&T); while (T--) { scanf("%d",&n); ans=(LL)F[n]*n; printf("%lld\n",ans); } }