第一道莫比烏斯反演題
要求的式子是 ∑ i = 1 n ∑ j = i + 1 n g c d ( i , j ) , n < = 2 ∗ 1 e 6 \sum_{i=1}^{n}\sum_{j=i+1}^{n}gcd(i,j),n<=2*1e6 ∑i=1n∑j=i+1ngcd(i,j),n<=2∗1e6,一組數據
可以轉換成 ∑ i = 1 n ∑ j = 1 n g c d ( i , j ) − ∑ i = 1 n g c d ( i , i ) 2 \frac{\sum_{i=1}^{n}\sum_{j=1}^{n}gcd(i,j)-\sum_{i=1}^{n}gcd(i,i)}{2} 2∑i=1n∑j=1ngcd(i,j)−∑i=1ngcd(i,i)
只要解決 ∑ i = 1 n ∑ j = 1 n g c d ( i , j ) \sum_{i=1}^{n}\sum_{j=1}^{n}gcd(i,j) ∑i=1n∑j=1ngcd(i,j)即可
常規套路(?)枚舉gcd
式子變成 ∑ p = 1 n p ∑ i = 1 n ∑ j = 1 n ( g c d ( i , j ) = p ) \sum_{p=1}^{n}p\sum_{i=1}^{n}\sum_{j=1}^{n}(gcd(i,j)=p) ∑p=1np∑i=1n∑j=1n(gcd(i,j)=p)
g c d ( i , j ) = p gcd(i,j)=p gcd(i,j)=p,必有 g c d ( i / p , j / p ) = 1 gcd(i/p,j/p)=1 gcd(i/p,j/p)=1
枚舉範圍可以除以 p p p,再轉換成 ∑ p = 1 n p ∑ i = 1 n / p ∑ j = 1 n / p ( g c d ( i , j ) = 1 ) \sum_{p=1}^{n}p\sum_{i=1}^{n/p}\sum_{j=1}^{n/p}(gcd(i,j)=1) ∑p=1np∑i=1n/p∑j=1n/p(gcd(i,j)=1)
( g c d ( i , j ) = 1 ) (gcd(i,j)=1) (gcd(i,j)=1)可以轉換成 ∑ d ∣ g c d ( i , j ) μ ( d ) \sum_{d|gcd(i,j)}\mu(d) ∑d∣gcd(i,j)μ(d)
式子變成 ∑ p = 1 n p ∑ i = 1 n / p ∑ j = 1 n / p ∑ d ∣ g c d ( i , j ) μ ( d ) \sum_{p=1}^{n}p\sum_{i=1}^{n/p}\sum_{j=1}^{n/p}\sum_{d|gcd(i,j)}\mu(d) ∑p=1np∑i=1n/p∑j=1n/p∑d∣gcd(i,j)μ(d)
嗯嗯式子怎麼越來越複雜了
開始提出 μ \mu μ,枚舉 d d d,式子變成 ∑ p = 1 n p ∑ d = 1 n μ ( d ) ⌊ n / p d ⌋ 2 \sum_{p=1}^{n}p\sum_{d=1}^{n}\mu(d){\lfloor n/pd \rfloor}^2 ∑p=1np∑d=1nμ(d)⌊n/pd⌋2
怎麼突然變成這樣?
因爲 d ∣ g c d ( i , j ) d|gcd(i,j) d∣gcd(i,j),有 d ∣ i d|i d∣i, d ∣ j d|j d∣j
μ ( d ) \mu(d) μ(d)被加上的次數是 1 − n / p 1-n/p 1−n/p中 d d d的倍數個數(合法的 i i i)乘上 1 − n / p 1-n/p 1−n/p中的 d d d的倍數個數(合法的 j j j),就是乘法原理
那 μ ( d ) \mu(d) μ(d)被加上的次數不就是 ⌊ n / p d ⌋ 2 {\lfloor n/pd \rfloor}^2 ⌊n/pd⌋2?
但是現在好像已經可以過了???
枚舉 p p p是 O ( n ) O(n) O(n)的,枚舉 d d d是 l o g log log的, ⌊ n / p d ⌋ 2 > 0 {\lfloor n/pd \rfloor}^2>0 ⌊n/pd⌋2>0時式子纔有值,實際上會更小。
n / 1 + n / 2 + n / 3 + . . + n / n ≈ n l o g n n/1+n/2+n/3+..+n/n\approx n log n n/1+n/2+n/3+..+n/n≈nlogn,就是 N O I P 2020 T 2 NOIP2020T2 NOIP2020T2的那個“調和級數”
2 ∗ 1 e 6 ∗ l o g ( 2 ∗ 1 e 6 ) < = 50000000 2*1e6*log(2*1e6)<=50000000 2∗1e6∗log(2∗1e6)<=50000000,沒有一點問題。
但是我們可以做到 O ( n ) O(n) O(n)。
令 T = p d T=pd T=pd。
我們再化化式子,變成了 ∑ T = 1 n ∑ p = 1 n p μ ( T / p ) ⌊ n / T ⌋ 2 \sum_{T=1}^{n}\sum_{p=1}^{n}p\mu(T/p){\lfloor n/T \rfloor}^2 ∑T=1n∑p=1npμ(T/p)⌊n/T⌋2
解釋一下:首先p可以放進去,這個就是乘法分配律。
根據乘法分配律, ⌊ n / T ⌋ 2 {\lfloor n/T \rfloor}^2 ⌊n/T⌋2可以提出來
式子變成 ∑ T = 1 n ⌊ n / T ⌋ 2 ∑ p = 1 n p μ ( T / p ) \sum_{T=1}^{n}{\lfloor n/T \rfloor}^2\sum_{p=1}^{n}p\mu(T/p) ∑T=1n⌊n/T⌋2∑p=1npμ(T/p)
然後 ∑ p = 1 n p μ ( T / p ) \sum_{p=1}^{n}p\mu(T/p) ∑p=1npμ(T/p)就是 φ ( T ) \varphi(T) φ(T)啊
如果想看證明戳這
式子變成 ∑ T = 1 n ⌊ n / T ⌋ 2 φ ( T ) \sum_{T=1}^{n}{\lfloor n/T \rfloor}^2\varphi(T) ∑T=1n⌊n/T⌋2φ(T)
線性篩 φ ( T ) \varphi(T) φ(T),可以達到 O ( n ) O(n) O(n)
事實上 ⌊ n / T ⌋ 2 {\lfloor n/T \rfloor}^2 ⌊n/T⌋2也可以整除分塊達到log級別,以用來對付多種數據
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 2000005
#define ll long long
using namespace std;
ll i,j,k,m,n,o,p,l,s,t;
ll pr[N],phi[N],bz[N];
int main()
{
freopen("gcdsum.in","r",stdin);
freopen("gcdsum.out","w",stdout);
scanf("%lld",&n);
phi[1]=1;
for (i=2;i<=N-5;i++)
{
if (!bz[i]) pr[++pr[0]]=i,bz[i]=1,phi[i]=i-1;
for (j=1;j<=pr[0]&&i*pr[j]<=N-5;j++)
{
bz[i*pr[j]]=1;
if (i%pr[j]) phi[i*pr[j]]=phi[i]*(pr[j]-1);
else phi[i*pr[j]]=pr[j]*phi[i];
if (!(i%pr[j])) break;
}
}
for (i=1;i<=n;i++) s+=(n/i)*(n/i)*phi[i];
s-=n*(n+1)/2;
printf("%lld\n",s>>1ll);
return 0;
}