题解:P1829 [集训队互测 2010] Crash的数字表格 / JZPTAB

· · 题解

假定

n\le m

P(n,m)=\sum_{i=1}^{n} \sum_{j=1}^m \operatorname{lcm}(i,j)

\operatorname{lcm}(i,j)=\frac{ij}{\gcd(i,j)}

改为求

P(n,m)=\sum_{i=1}^{n} \sum_{j=1}^m \frac{ij}{\gcd(i,j)}

枚举 \gcd(i,j) 的取值,改为求

P(n,m)=\sum_{g=1}^n g \sum_{i=1}^{\lfloor \frac{n}{g} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{g} \rfloor } ij[\gcd(i,j)=1]

{1(n)*\mu(n)=\varepsilon(n)}

n=\gcd(i,j)

P(n,m)=\sum_{g=1}^n g \sum_{i=1}^{\lfloor \frac{n}{g} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{g} \rfloor } ij\sum_{d|\gcd(i,j)}\mu(d)

S(n,m)=\sum_{i=1}^{\lfloor \frac{n}{g} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{g} \rfloor } ij\sum_{d|\gcd(i,j)}\mu(d)

交换求和次序得

S(n,m)=\sum_{d|\gcd(i,j)}\sum_{i=1}^n \sum_{j=1}^m ij\mu(d)

考虑换为枚举 d,得

S(n,m)=\sum_{d=1}^n\sum_{d|i}^n \sum_{d|j}^m ij\mu(d)

等价于

S(n,m)=\sum_{d=1}^n \sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor} ij\mu(d)d^2

整理得

S(n,m)=\sum_{d=1}^n \mu(d)d^2\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \sum_{j=1}^{\lfloor \frac{m}{d} \rfloor} ij

考虑令

T(n,m)=\sum_{i=1}^{n} \sum_{j=1}^{m} ij

求和得

T(n,m)=\frac{n(n+1)m(m+1)}{4}

S(n,m)=\sum_{d=1}^n \mu(d)d^2T({\lfloor \frac{n}{d} \rfloor},{\lfloor \frac{m}{d} \rfloor})

代回原目标式

P(n,m)=\sum_{g=1}^n g S({\lfloor \frac{n}{d} \rfloor},{\lfloor \frac{m}{d} \rfloor}) 代码: ```cpp #include <bits/stdc++.h> #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define per(i,a,b) for(int i=(a);i>=(b);i--) #define int long long using namespace std; const int N=1e7+91,mod=20101009; int not_prime[N],miu[N],pre[N]; vector <int> prime; void get_miu(int n){ miu[1]=1,not_prime[1]=1; rep(i,2,n){ if(!not_prime[i]){ miu[i]=-1; prime.push_back(i); } for(auto v:prime){ if(i*v>n) break; not_prime[i*v]=1; if(i%v==0){ miu[i*v]=0; break; } miu[i*v]=-miu[i]; } } } int T(int n,int m){ return ((n*(n+1)/2)%mod)*((m*(m+1)/2)%mod)%mod; } int S(int n,int m){ int sum=0,l=1,r=1; while(l<=n){ r=min((n/(n/l)),(m/(m/l))); sum=(sum+(pre[r]-pre[l-1]+mod)%mod*T(n/l,m/l)%mod)%mod; l=r+1; } return sum; } signed main(){ int n,m; cin>>n>>m; if(n>m) swap(n,m); get_miu(1e7); rep(i,1,n) pre[i]=(pre[i-1]+i*i*miu[i]+mod)%mod; int sum=0,l=1,r=1; while(l<=n){ r=min((n/(n/l)),(m/(m/l))); sum=(sum+(((r-l+1)*(l+r)/2)%mod)*S(n/l,m/l)%mod)%mod; l=r+1; } cout<<sum; return 0; } ```