n<=1e10,求1<=i<=n,1<=j<=n,lcm(i,j)的和。
又是充滿坎坷的簡單題。。。
Wait a minute 先打個miu和phi的表,以及一個暴力,隨時檢查式子!
來吧!
$\sum_{i=1}^{n}\sum_{j=1}^{n}[i,j]$
$=\sum_{i=1}^{n}\sum_{j=1}^{n}ij(i,j)^{-1}$
$=\sum_{d=1}^{n}d^{-1}\sum_{i=1}^{n}\sum_{j=1}^{n}ij[(i,j)=d]$
停住!
這里是一個重要抉擇,后面怎么變換直接決定了做出這題的難度以及代碼復雜度!!!
一、直接反演
$=\sum_{d=1}^{n}d^{-1}\sum_{d|t,t\leqslant n}\mu (\frac{t}{d})t^2(\frac{(1+\left \lfloor \frac{n}{t} \right \rfloor)\left \lfloor \frac{n}{t} \right \rfloor}{2})^2$
$=\sum_{t=1}^{n}t^2(\frac{(1+\left \lfloor \frac{n}{t} \right \rfloor)\left \lfloor \frac{n}{t} \right \rfloor}{2})^2\sum_{d|t}d^{-1}\mu(\frac{t}{d})$
閃一句:兩個t丟后面。
$=\sum_{t=1}^{n}(\frac{(1+\left \lfloor \frac{n}{t} \right \rfloor)\left \lfloor \frac{n}{t} \right \rfloor}{2})^2(t\sum_{d|t}d\mu(d))$
需要求后面那堆的前綴和。轉移戰線:
$\sum_{t=1}^{n}t\sum_{d|t}d\mu(d)$
$=\sum_{t=1}^{n}\sum_{d|t}td\mu(d)$
$=\sum_{k=1}^{n}\sum_{d=1}^{\left \lfloor \frac{n}{k} \right \rfloor}kd^2\mu(d)$
$=\sum_{d=1}^{n}d^2\mu(d)\sum_{k=1}^{\left \lfloor \frac{n}{d} \right \rfloor}k$
$=\sum_{d=1}^{n}(\frac{(1+\left \lfloor \frac{n}{d} \right \rfloor)\left \lfloor \frac{n}{d} \right \rfloor}{2})d^2\mu(d)$
好的!只需要一個$d^2\mu(d)$的前綴和即可。配倆Id(x)=x給他卷積:
$\sum_{i=1}^{n}\sum_{d|i}d^2\mu(d)(\frac{i}{d})^2$
$=\sum_{k=1}^{n}k^2\sum_{d=1}^{\left \lfloor \frac{i}{k} \right \rfloor}d^2\mu(d)$
於是$\sum_{i=1}^{n}i^2\mu(i)=1-\sum_{k=2}^{n}k^2\sum_{i=1}^{\left \lfloor \frac{n}{k} \right \rfloor}d^2\mu(d)$
套了若干個,還是$n^{\frac{2}{3}}$。但這代碼量就。。
二、反演個鬼
$\sum_{d=1}^{n}d^{-1}\sum_{i=1}^{n}\sum_{j=1}^{n}ij[(i,j)=d]$
$=\sum_{d=1}^{n}d\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{n}{d} \right \rfloor}ij[(i,j)=1]$
$=\sum_{d=1}^{n}d((2\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}i\sum_{j=1}^{i}j[(i,j)=1])-1)$
$=\sum_{d=1}^{n}d((2\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}i\frac{i\varphi(i)+[i=1]}{2})-1)$
$=\sum_{d=1}^{n}d((\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}i^2\varphi(i)+[i=1])-1)$
$=\sum_{d=1}^{n}d\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}i^2\varphi(i)$
接着就是$i^2\varphi(i)$的前綴和啦!一樣丟倆Id(x)=x給他卷積:
$\sum_{i=1}^{n}\sum_{d|i}d^2\varphi(d)(\frac{i}{d})^2$
$=\sum_{k=1}^{n}k^2\sum_{d=1}^{\left \lfloor \frac{n}{k} \right \rfloor}d^2\varphi(d)$
得$\sum_{i=1}^{n}i^2\varphi(i)=(\frac{n(n+1)}{2})^2-\sum_{k=2}^{n}k^2\sum_{i=1}^{\left \lfloor \frac{n}{k} \right \rfloor}i^2\varphi(i)$
大功告成。
首先從正確性來說的話,以后一定要先打好表和暴力再來推,推兩句檢查一次。因為一半有推的人都可以推到類似nln(n)的復雜度,就算最后推不出正解,較多的暴力還是可以拿到的。
然后多嘗試把不同的東西提出來,不要怕失敗。
至於說這題兩種不同的推法得到了兩種時間相同但編碼復雜度差別較大的方法,我認為是在學數論初期是難免的。多總結多鍛煉也許就能少走彎路。

1 #include<string.h> 2 #include<stdlib.h> 3 #include<stdio.h> 4 #include<math.h> 5 //#include<assert.h> 6 #include<algorithm> 7 //#include<iostream> 8 //#include<bitset> 9 using namespace std; 10 11 #define LL long long 12 LL n,m; 13 #define maxn 5000011 14 const int mod=1e9+7; 15 int phi[maxn],sumphi[maxn],prime[maxn],lp; bool notprime[maxn]; 16 17 void pre(int n) 18 { 19 phi[1]=1; sumphi[1]=1; 20 for (int i=2;i<=n;i++) 21 { 22 if (!notprime[i]) {prime[++lp]=i; phi[i]=i-1;} 23 sumphi[i]=sumphi[i-1]+1ll*i*i%mod*phi[i]%mod; 24 sumphi[i]-=sumphi[i]>=mod?mod:0; 25 for (int tmp,j=1;j<=lp && 1ll*prime[j]*i<=n;j++) 26 { 27 notprime[tmp=prime[j]*i]=1; 28 if (i%prime[j]) phi[tmp]=phi[i]*(prime[j]-1); 29 else {phi[tmp]=phi[i]*prime[j]; break;} 30 } 31 } 32 } 33 34 struct Edge{LL to; int v,next;}; 35 #define maxh 1000007 36 struct Hash 37 { 38 int first[maxh],le; Edge edge[maxn]; 39 Hash() {le=2;} 40 void insert(LL y,int v) {int x=y%maxh; Edge &e=edge[le]; e.to=y; e.v=v; e.next=first[x]; first[x]=le++;} 41 int find(LL y) {int x=y%maxh; for (int i=first[x];i;i=edge[i].next) if (edge[i].to==y) return edge[i].v; return -1;} 42 }h; 43 44 int two=(mod+1)/2,six=(mod+1)/6; 45 int calc(LL n) 46 { 47 if (n<=m) return sumphi[n]; 48 int tmp=h.find(n); if (tmp!=-1) return tmp; 49 int ans=(n%mod)%mod*((n+1)%mod)%mod*(n%mod)%mod*((n+1)%mod)%mod*two%mod*two%mod; 50 for (LL i=2,last;i<=n;i=last+1) 51 { 52 last=n/(n/i); 53 ans-=((last%mod)%mod*((last+1)%mod)%mod*((last+last+1)%mod)%mod*six%mod 54 -((i-1)%mod)%mod*(i%mod)%mod*((i+i-1)%mod)%mod*six%mod)*calc(n/i)%mod; 55 ans+=ans<0?mod:0; ans-=ans>=mod?mod:0; 56 } 57 h.insert(n,ans); 58 return ans; 59 } 60 61 int main() 62 { 63 scanf("%lld",&n); 64 m=pow(n,2.0/3); pre(m); 65 int ans=0; 66 for (LL i=1,last;i<=n;i=last+1) 67 { 68 last=n/(n/i); 69 ans+=((last-i+1)%mod)*((last+i)%mod)%mod*two%mod*calc(n/i)%mod; 70 ans-=ans>=mod?mod:0; 71 } 72 printf("%d\n",ans); 73 return 0; 74 }