链接
https://ac.nowcoder.com/acm/contest/549/J
题意
$\sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)^2$ $(n,m\le 1e6)$
思路一
$\begin{aligned}
& \sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)^2 \
= & \sum_{d=1}d^2\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=d] \
\end{aligned}$
记 $f(d)=\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=d]$
记 $F(t)=\sum_{d\mid t}f(d)=\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor$
$f(d)=\sum_{d\mid t}\mu(\frac{t}{d})F(t)=\sum_{d\mid t}\mu(\frac{t}{d})\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor$
枚举 $d$ 的倍数 $O(nlogn)$ 求解。
代码一
| 12
 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
 
 | #include <bits/stdc++.h>#define SZ(x) (int)(x).size()
 #define ALL(x) (x).begin(),(x).end()
 #define PB push_back
 #define EB emplace_back
 #define MP make_pair
 #define FI first
 #define SE second
 using namespace std;
 typedef double DB;
 typedef long double LD;
 typedef long long LL;
 typedef unsigned long long ULL;
 typedef pair<int,int> PII;
 typedef vector<int> VI;
 typedef vector<PII> VPII;
 
 const LL MOD=1e9+7;
 const int N=1e6+5;
 int mn[N],mu[N];
 VI p;
 void get_mu(int n) {
 mu[1]=1;
 for(int i=2;i<=n;i++) {
 if(!mn[i]) mn[i]=i,mu[i]=-1,p.PB(i);
 for(auto x:p) {
 if(x*i>n) break;
 mn[x*i]=x;
 if(i%x==0) {mu[x*i]=0;break;}
 mu[x*i]=-mu[i];
 }
 }
 }
 int main() {
 ios::sync_with_stdio(false);
 cin.tie(nullptr);
 int n,m;cin>>n>>m;
 get_mu(1e6);
 LL res=0;
 int lim=min(n,m);
 for(int i=1;i<=lim;i++) {
 for(int j=i;j<=lim;j+=i) {
 res=(res+1ll*i*i%MOD*mu[j/i]*(n/j)%MOD*(m/j)%MOD)%MOD;
 }
 }
 cout<<res<<'\n';
 return 0;
 }
 
 | 
思路二
$\begin{aligned}
& \sum_{i=1}^n\sum_{j=1}^m\gcd(i,j)^2 \
= & \sum_{d=1}d^2\sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=d] \
= & \sum_{d=1}d^2\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1] \
\end{aligned}$
记 $g(n,m)=\sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)=1]=\sum_{d=1}\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor$
记 $f(n,m)=\sum_{d=1}d^2g(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor)$
做两次数论分块。
代码二
| 12
 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
 
 | #include <bits/stdc++.h>#define SZ(x) (int)(x).size()
 #define ALL(x) (x).begin(),(x).end()
 #define PB push_back
 #define EB emplace_back
 #define MP make_pair
 #define FI first
 #define SE second
 using namespace std;
 typedef double DB;
 typedef long double LD;
 typedef long long LL;
 typedef unsigned long long ULL;
 typedef pair<int,int> PII;
 typedef vector<int> VI;
 typedef vector<PII> VPII;
 
 const LL MOD=1e9+7;
 const int N=1e6+5;
 int mn[N];
 LL mu[N],sum[N];
 VI p;
 void get_mu(int n) {
 mu[1]=1;
 for(int i=2;i<=n;i++) {
 if(!mn[i]) mn[i]=i,mu[i]=-1,p.PB(i);
 for(auto x:p) {
 if(x*i>n) break;
 mn[x*i]=x;
 if(i%x==0) {mu[x*i]=0;break;}
 mu[x*i]=-mu[i];
 }
 }
 for(int i=1;i<=n;i++) mu[i]=(mu[i-1]+MOD+mu[i])%MOD;
 for(int i=1;i<=n;i++) sum[i]=(sum[i-1]+1ll*i*i%MOD)%MOD;
 }
 LL g(int n,int m) {
 int lim=min(n,m);
 LL ret=0;
 for(int l=1,r;l<=lim;l=r+1) {
 r=min(n/(n/l),m/(m/l));
 ret=(ret+(mu[r]+MOD-mu[l-1])%MOD*(n/l)%MOD*(m/l)%MOD)%MOD;
 }
 return ret;
 }
 LL f(int n,int m) {
 int lim=min(n,m);
 LL ret=0;
 for(int l=1,r;l<=lim;l=r+1) {
 r=min(n/(n/l),m/(m/l));
 ret=(ret+(sum[r]+MOD-sum[l-1])%MOD*g(n/l,m/l)%MOD)%MOD;
 }
 return ret;
 }
 int main() {
 ios::sync_with_stdio(false);
 cin.tie(nullptr);
 int n,m;cin>>n>>m;
 get_mu(1e6);
 cout<<f(n,m)<<'\n';
 return 0;
 }
 
 |