标签:bre putc main 表示 efi etc 不同 莫比乌斯反演 turn
膜一发rqy
真正的学习了莫比乌斯反演后,感觉与以前做题完全不同了(飞升的感觉
居中的式子是大体思路
题目让我们求
$$\sum_{i=1}^n\sum_{j=1}^mgcd(i , j) == p$$
显然有一个结论$d | gcd(i,j) ? d | i , d | j$
我们继续推
$f(i)表示i是不是质数,如果是的话,f(i) = 1,不是f(i) = 0$
$$\sum_{i=1}^n\sum_{i=1}^mf(gcd(i,j))$$
反演$$f(n) = \sum_{d|n}^ng(d)$$
就有$g(n) = \sum_{d|n}f(d)\mu (\dfrac{n}{d})$
$g(n) = \sum_{p\mid n}\mu\left(\frac np\right)(p为质数)$
$$\sum_{i=1}^n\sum_{i=1}^m\sum_{d|gcd(i,j)}g(d)$$
根据结论:
$$\sum_{i=1}^n\sum_{j=1}^m\sum_{d|i,d|j}g(d)$$
换个枚举点
$$\sum_{d=1}^{min(n,m)}g(d)\sum_{i=1}^n\sum_{j=1}^m{[d|i][d|j]}$$
$$\sum_{d=1}^{min(n,m)}g(d)[\dfrac{n}{d}][\dfrac{m}{d}]$$
推完了
用整除分块做
前面的式子可以用前缀和维护.
// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#define rep(i , x, p) for(register int i = x;i <= p;++ i)
#define sep(i , x, p) for(register int i = x;i >= p;-- i)
#define gc getchar()
#define pc putchar
#define ll long long
using std::max;
using std::swap;
const int maxN = 1e7 + 7;
const int N = 10000000;
inline int gi() {register int x = 0,f = 1;char c = gc;while(c < ‘0‘ || c > ‘9‘) {if(c == ‘-‘)f = -1;c = gc;}while(c >= ‘0‘ && c <= ‘9‘) {x = x * 10 + c - ‘0‘;c = gc;}return x * f;}
void print(ll x) {if(x < 0) pc(‘-‘) , x = -x;if(x >= 10) print(x / 10);pc(x % 10 + ‘0‘);}
inline int min(int a , int b) {return a > b ? b : a;}
int mu[maxN] , g[maxN], prime[maxN], num;
bool vis[maxN];
void init() {
mu[1] = 1;
rep(i , 2, N) {
if(!vis[i]) {prime[++ num] = i;mu[i] = -1;}
for(register int j = 1;j <= num && i * prime[j] <= N;++ j) {
vis[i * prime[j]] = true;
if(i % prime[j] == 0) break;
mu[i * prime[j]] -= mu[i];
}
}
rep(i , 1, num) {
for(register int p = prime[i] , j = 1;j * p <= N;++ j)
g[j * p] += mu[j];
}
rep(j , 1, N) g[j] += g[j - 1];
}
inline ll work(int n , int m) {
ll sum = 0;
int tmp = min(n , m);
for(register int l = 1 , r;l <= tmp;l = r + 1){
r = min(n / (n / l) , m / (m / l));
sum += (ll)(n / l) * (m / l) * (g[r] - g[l - 1]) ;
}
return sum;
}
int main() {
init();
int T = gi();
while(T --) {
int n = gi() , m = gi();
print(work(n , m));pc(‘\n‘);
}
return 0;
}
标签:bre putc main 表示 efi etc 不同 莫比乌斯反演 turn
原文地址:https://www.cnblogs.com/gzygzy/p/10121656.html