正题
题目链接:https://www.luogu.com.cn/problem/P3768
题目大意
给出n,pn,pn,p求∑i=1n∑j=1ngcd(i,j)∗i∗j\sum_{i=1}^n\sum_{j=1}^ngcd(i,j)*i*ji=1∑nj=1∑ngcd(i,j)∗i∗j模ppp的值。
解题思路
下文中定义Hy(x)=∑i=1xiyH_y(x)=\sum_{i=1}^xi^yHy(x)=∑i=1xiy
首先显然是上莫反推式子f(x)=∑i=1n∑j=1n[gcd(i,j)==x]∗i∗j=x2∑i=1⌊nx⌋∑j=1⌊nx⌋ij[gcd(i,j)==1]f(x)=\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)==x]*i*j=x^2\sum_{i=1}^{\lfloor\frac{n}{x}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{x}\rfloor}ij[gcd(i,j)==1]f(x)=i=1∑nj=1∑n[gcd(i,j)==x]∗i∗j=x2i=1∑⌊xn⌋j=1∑⌊xn⌋ij[gcd(i,j)==1]
F(x)=∑x∣df(d)=x2∑i=1⌊nx⌋∑j=1⌊nx⌋ij=x2H1(⌊nx⌋)2F(x)=\sum_{x|d}f(d)=x^2\sum_{i=1}^{\lfloor\frac{n}{x}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{x}\rfloor}ij=x^2H_1(\lfloor\frac{n}{x}\rfloor)^2F(x)=x∣d∑f(d)=x2i=1∑⌊xn⌋j=1∑⌊xn⌋ij=x2H1(⌊xn⌋)2
然后答案为∑x=1nf(x)=∑x=1nx2∑x∣dF(d)μ(xd)=∑d=1nF(d)∑x∣dμ(xd)x2\sum_{x=1}^nf(x)=\sum_{x=1}^nx^2\sum_{x|d}F(d)\mu(\frac{x}{d})=\sum_{d=1}^nF(d)\sum_{x|d}\mu(\frac{x}{d})x^2x=1∑nf(x)=x=1∑nx2x∣d∑F(d)μ(dx)=d=1∑nF(d)x∣d∑μ(dx)x2
展开F(x)F(x)F(x)有
∑d=1nH1(⌊nd⌋)2d2∑x∣dμ(xd)x2\sum_{d=1}^nH_1(\lfloor\frac{n}{d}\rfloor)^2d^2\sum_{x|d}\mu(\frac{x}{d})x^2d=1∑nH1(⌊dn⌋)2d2x∣d∑μ(dx)x2
前面可以整除分块,问题变为了如何求d2∑x∣dμ(xd)x2d^2\sum_{x|d}\mu(\frac{x}{d})x^2d2∑x∣dμ(dx)x2的前缀和
因为nnn很大,所以我们考虑使用杜教筛。
先考虑一个式子μ∗I=ϵ⇒μ∗I∗φ=ϵ∗φ⇒μ∗id=φ\mu*I=\epsilon\ \ \ \Rightarrow\ \ \ \mu*I*\varphi=\epsilon *\varphi\ \ \ \Rightarrow\ \ \ \mu*id=\varphiμ∗I=ϵ ⇒ μ∗I∗φ=ϵ∗φ ⇒ μ∗id=φ
所以上面那个东西就可以变成∑d=1nH1(⌊nd⌋)2d2φ(d)\sum_{d=1}^nH_1(\lfloor\frac{n}{d}\rfloor)^2d^2\varphi(d)d=1∑nH1(⌊dn⌋)2d2φ(d)
上杜教筛f(n)=φ(n)n2,g(n)=n2f(n)=\varphi(n)n^2,g(n)=n^2f(n)=φ(n)n2,g(n)=n2,f(n)g(n)=∑d∣nf(d)g(nd)=∑d∣nφ(d)d2∗n2d2=n2∑d∣nφ(d)=n3f(n)g(n)=\sum_{d|n}f(d)g(\frac{n}{d})=\sum_{d|n}\varphi(d)d^2*\frac{n^2}{d^2}=n^2\sum_{d|n}\varphi(d)=n^3f(n)g(n)=d∣n∑f(d)g(dn)=d∣n∑φ(d)d2∗d2n2=n2d∣n∑φ(d)=n3
然后有结论H3(n)=H1(n)2H_3(n)=H_1(n)^2H3(n)=H1(n)2,具体证明就用数学归纳法把,大致是多了一个n+1n+1n+1之后前者会多一个(n+1)3(n+1)^3(n+1)3,后者会多一个2∗H1(n)∗(n+1)+(n+1)2=(n+1)32*H_1(n)*(n+1)+(n+1)^2=(n+1)^32∗H1(n)∗(n+1)+(n+1)2=(n+1)3。这样就可以O(n23)O(n^\frac{2}{3})O(n32)的筛我们需要的东西了。
然后就是套莫反了,值得一提的是H2(n)=n∗(n+1)∗(2n+1)6H_2(n)=\frac{n*(n+1)*(2n+1)}{6}H2(n)=6n∗(n+1)∗(2n+1),大体上也是数学归纳法证明吧。
理论上时间复杂度应该是O(n23n)O(n^\frac{2}{3}\sqrt n)O(n32n)的,但是因为杜教筛的记忆化还有各种原因所以实际上其实跑的快很多了。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#define ll long long
using namespace std;
const ll N=8e6;
ll n,p,cnt,inv2,inv6;
ll phi[N],pri[N];bool v[N];
map<ll,ll> mark;
void Prime(){phi[1]=1;for(ll i=2;i<N;i++){if(!v[i])pri[++cnt]=i,phi[i]=i-1;for(ll j=1;j<=cnt&&i*pri[j]<N;j++){v[i*pri[j]]=1;if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}phi[i*pri[j]]=phi[i]*(pri[j]-1);}}for(ll i=1;i<N;i++)phi[i]=(phi[i-1]+phi[i]%p*i%p*i%p)%p;return;
}
ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%p;x=x*x%p;b>>=1;}return ans;
}
ll s1(ll x)
{x%=p;return x*(x+1)%p*inv2%p;}
ll s2(ll x)
{x%=p;return x*(x+1)%p*(x+x+1)%p*inv6%p;}
ll Sum(ll x){if(x<N)return phi[x];if(mark[x])return mark[x];ll ans=s1(x);ans=ans*ans%p;for(ll l=2,r;l<=x;l=r+1){r=x/(x/l);(ans-=(s2(r)-s2(l-1))*Sum(x/l)%p)%=p;}return mark[x]=(ans+p)%p;
}
int main()
{scanf("%lld%lld",&p,&n);inv2=power(2,p-2);inv6=power(6,p-2);Prime();ll ans=0;for(ll l=1,r;l<=n;l=r+1){r=n/(n/l);ll tmp=s1(n/l);tmp=tmp*tmp%p;(ans+=(Sum(r)-Sum(l-1)+p)%p*tmp%p)%=p;}printf("%lld\n",ans);
}