math
求 S(n) = ∑i∈[1,n]∑j∈[1,n] F(i,j),n<=109
F(i,j) = ∑d∈[1,i*j] [d | i*j]
1. 化简S(n)
step 1.
F(i,j) = ∑d∈[1,i*j] [d/gcd(i,d) | i*j/gcd(i,d)]
= ∑d∈[1,i*j] [d/gcd(i,d) | j]
step 2.
S(n) = ∑i∈[1,n]∑j∈[1,n]∑d∈[1,i*j] [d/gcd(i,d) | j]
= ∑i∈[1,n]∑d∈[1,i*n] [n/(d/gcd(i,d)]
= ∑i∈[1,n]∑d∈[1,i*n] [n*gcd(i,d)/d]
step 3.
S(n) = ∑i∈[1,n]∑d∈[1,i*n]∑k [gcd(i,d)==k]*[n*k/d]
= ∑k∑i∈[1,n/k]∑d∈[1,n] [gcd(i,d)==1]*[n/d]
S(n) = ∑i∈[1,n]∑d∈[1,n]∑k∈[1,n/i] [gcd(i,d)==1]*[n/d]
= ∑i∈[1,n]∑d∈[1,n] [gcd(i,d)==1]*[n/d]*[n/i]
S(n) = ∑i∈[1,n]∑j∈[1,n] [gcd(i,j)==1]*[n/i]*[n/j]
step 4.
S(n) = ∑d μ(d)*∑i∈[1,n/d] ∑j∈[1,n/d] [n/(id)]*[n/(jd)]
= ∑d μ(d)*∑i∈[1,n/d] [n/(id)]*∑j∈[1,n/d] [n/(jd)]
令g(n) = ∑i∈[1,n] [n/i],则S(n) = ∑d μ(d)*g([n/d])2
只计算所有不同的[n/d],可以做到O(n2/3)
2.0 计算M(n) = ∑i∈[1,n] μ(i)
M(n) = ∑i∈[1,n] μ(i)
= ∑i∈[1,n] (∑d|i μ(d) - ∑d|i,d<i μ(d))
= 1 - ∑i∈[1,n]∑d|i,d<i μ(d)
= 1 - ∑d|i,d<i∑i∈[1,n] μ(d)
= 1 - ∑d∈[1,n] ∑i∈[2,n/d] μ(d)
= 1 - ∑i∈[2,n] ∑d∈[1,n/i] μ(d)
= 1 - ∑i∈[2,n] M([n/i])
筛出n2/3以内的M,查询的时候查表O(1)回答.
对于大于n2/3的情况,我们用hash表来记忆化.
这样能做到O(n2/3)的复杂度.
2.1 计算F(n) = ∑i∈[1,n] phi(i)
由n = ∑d|n phi(d) ,我们可以类似地得到F(n)的计算方法
F(n) = ∑i∈[1,n] phi(i)
= ∑i∈[1,n] (∑d|i phi(d) - ∑d|i,d<i phi(d))
= n(n+1)/2 - ∑i∈[1,n]∑d|i,d<i phi(d)
= n(n+1)/2 - ∑i∈[2,n] F([n/i])
3. 码码码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | <span style= "font-family: comic sans ms,cursive;" >#include <vector> #include <stdio.h> #include <string.h> #include <algorithm> #define MAXN 1000005 #define SIZE ((1<<18)-1) #define Mod 1000000007 using namespace std; typedef long long ll; namespace Mobius{ bool ban[MAXN]; vector< int >p; int n,mu[MAXN],ptot; inline void linear_shake( int n){ mu[1]=1; for ( int i=2;i<=n;++i){ if (!ban[i]){ ++ptot; p.push_back(i); mu[i]=Mod-1; } for ( int j=0,k;j<ptot;++j){ if ((ll)i*p[j]>n) break ; ban[k=i*p[j]]=1; if (i%p[j]){ mu[k]=Mod-mu[i]; } else { mu[k]=0; break ; } } } for ( int i=2;i<=n;++i){ mu[i]=(mu[i]+mu[i-1])%Mod; } } int set[MAXN],f[MAXN]; int head[SIZE+1],tot,next[MAXN]; inline int M( int x){ if (!ptot)linear_shake(n=1000000); if (x<=n) return mu[x]; int p=x&SIZE; for ( int i=head[p];i;i=next[i]) if (set[i]==x){ return f[i]; } int res=1; for ( int i=2,j;i<=x;i=j+1){ j=x/(x/i); res=(res+Mod-ll(j-i+1)*M(x/i)%Mod)%Mod; } int o=++tot; set[o]=x,f[o]=res; next[o]=head[p],head[p]=o; return res; } }; inline void set_IO(){ freopen ( "math.in" , "r" ,stdin); freopen ( "math.out" , "w" ,stdout); } inline int g( int n){ int res=0; for ( int i=1,j;i<=n;i=j+1){ j=n/(n/i); res=(res+ll(j-i+1)*(n/i)%Mod)%Mod; } return res; } int n,ans; int main(){ set_IO(); scanf ( "%d" ,&n); for ( int i=1,j,k;i<=n;i=j+1){ j=n/(n/i); k=g(n/i),k=(ll)k*k%Mod; k=(ll)k*((Mobius::M(j)+Mod-Mobius::M(i-1))%Mod)%Mod; ans=(ans+k)%Mod; } printf ( "%d\n" ,ans); return 0; }</span> |