先咕着
求
\[\large \sum_{i=1}^{n} \sum_{j=1}^{m}[gcd(i,j)](n<m)\]
显然
\[\large\sum_{d|n}\varphi(d)=n\]
所以
\[\large\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d|gcd(i,j)}\varphi(d)\]
\[\large=\sum_{d=1}^{n}\varphi(d)*\lfloor\frac{n}{d}\rfloor*\lfloor\frac{m}{d}\rfloor\]
代码大概长这样(?
预处理
void init(int x) {
vis[1] = 1 ; mul[1] = 1 ;
for(int i = 2 ; i <= x ; i ++) {
if(! vis[i]) {
mul[i] = -1 ;
prm[++ cnt] = i ;
}
for(int j = 1 ; j <= cnt && i * prm[j] <= x ; j ++) {
int k = i * prm[j] ;
vis[k] = true ;
if(! (i % prm[j])) { break ; }
else mul[k] = -mul[i] ;
}
}
for(int i = 1 ; i <= x ; i ++) { pre[i] = pre[i - 1] + mul[i] ; }
}
for(int l = 1 , r = 0 ; l <= min(n , m) ; l = r + 1) {
r = min(n / (n / l) , m / (m / l)) ;
ans += 1ll * (n / l) * (m / l) * (sum[r] - sum[l - 1]) ;
}
求 \(\large \sum_{i=1}^{n}\sum_{i=1}^{m}[gcd(i,j)==d]\)
显然刚开始的套路是
\[\large \sum_{i=1}^{\lfloor \frac{n}{d}\rfloor}\sum_{i=1}^{\lfloor \frac{m}{d} \rfloor}[gcd(i,j)==1]\]
扫描二维码关注公众号,回复:
8046139 查看本文章
然后直接对 \(\lfloor \frac{n}{d} \rfloor\) \(\lfloor \frac{m}{d} \rfloor\) 做一个 \(\sum_{i=1}^{n}\sum_{j=1}{m}[gcd(i,j)==1]\)
普通的数论分块即可…
#include <bits/stdc++.h>
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define rep(i , j , k) for(int i = j ; i <= k ; i ++)
#define Rep(i , j , k) for(int i = j ; i >= k ; i --)
#define int long long
using namespace std ;
using ll = long long ;
using pii = pair <int , int> ;
using vii = vector <int> ;
auto ot = [&]() { cerr << "ATS TXDY" << '\n' ; int ATS_nantf_txdy = true ; } ;
auto _ios = [&]() { ios :: sync_with_stdio(false) ; cin.tie(nullptr) ; cout.tie(nullptr) ; } ;
namespace stO_ATS_Orz {
template < class T > void cmax(T & x , T y) { if(x > y) x = y ; }
template < class T > void cmin(T & x , T y) { if(x < y) x = y ; }
template < class T > void abs(T x) { if(x < 0) x = -x ; }
const int N = 5e4 + 10 ;
int t , n , m , k ;
int prm[N] , mul[N] , pre[N] , cnt = 0 ;
bool vis[N] ;
void init(int x) {
vis[1] = 1 ; mul[1] = 1 ;
for(int i = 2 ; i <= x ; i ++) {
if(! vis[i]) {
mul[i] = -1 ;
prm[++ cnt] = i ;
}
for(int j = 1 ; j <= cnt && i * prm[j] <= x ; j ++) {
int k = i * prm[j] ;
vis[k] = true ;
if(! (i % prm[j])) { break ; }
else mul[k] = -mul[i] ;
}
}
for(int i = 1 ; i <= x ; i ++) { pre[i] = pre[i - 1] + mul[i] ; }
}
void main() {
init(5e4) ;
cin >> t ;
while(t --) {
cin >> n >> m >> k ;
n /= k ;
m /= k ;
int ans = 0 ;
for(int l = 1 , r = 0 ; l <= min(n , m) ; l = r + 1) {
r = min(n / (n / l) , m / (m / l)) ;
ans += (n / l) * (m / l) * (pre[r] - pre[l - 1]) ;
}
cout << ans << '\n' ;
}
}
}
signed main() {
_ios() ; ot() ;
return stO_ATS_Orz :: main() , 0 ;
}
求 \(\large \sum_{i=1}^{n}\sum_{j=1}{m}[gcd(i,j)\in prime]\)
(prime 为 质数)
这样每次就不能单纯的使用前缀和\(sum\)直接加上\(\mu(i)\)了