关于莫比乌斯
莫比乌斯函数
也就是那个\(\mu(i)\) , 这个东西可以线性筛。
\(\mu(i] = \begin{cases} 1 \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1 \\ p_1 ^ {k_1}p_2^{k_2}...p_m^{k_m} \ \ (-1)^m \\ else \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0 \end{cases}\)
两个性质
- \(\sum_{d | n} \mu(d) = [n = 1]\)
- \(\sum_{d | n} \frac{\mu(d)}{d} = \frac{\phi(n)}{n}\)
第一个证明:
根据定义,有超过一次的质因子都是0,那么只用考虑有没有某个质因子,也可以抽象成,有一堆的质因子,每一个上都可以填零或者填一,显然1的个数为奇数时ans=-1 , 否则ans=1。
也就是看\(0 - ((1<<n)-1)\)中1的个数为奇数的-1的个数为偶数的显然ans=0(n != 1)
第二个证明:
这个就简单一点,全部通分,就是一个简单的容斥,
莫比乌斯反演
\(F[n] = \sum_{d | n} f(n)\)
\(f[n] = \sum_{d | n} \mu(d) F[n / d]\)
这个仍然可以用容斥来理解。
把所有n的约数取出,f(d)扔到一个数组里。要求的是最后一个f(n)
根据容斥,我们可以先加上所有的\(\mu(1) * F[n / 1] = F[n] = \sum_{d | n} f[d]\)
然后减去F[n / 2] , F[n / 3] (假设2,3是它的约数,意会一下)
然后再加上F[n / 6]
据说还有个式子
\(F[n] = \sum_{n | d} f[d]\)
\(f[n] = \sum_{n | d} F[d] * \mu(d / n)\)
P2522 [HAOI2011]Problem b
对于给出的 n 个询问,每次求有多少个数对 (x,y),满足 a <= x <= b , c <= y <= d ,且 gcd(x,y) = k; 所有出现的数 <= 5e4
这个是个经典的题
用之前的反演练习一下。
设f(x) 为gcd(i , j) = x 的对数
设F(x) 为 x | gcd(i , j) 的对数
那么显然 \(F[x] = \sum_{x | d} f[d]\)
反演可得 \(f[x] = \sum_{x | d} \mu(d / x) F[d]\)
再来考虑F[x]是啥。\(F[x] = \frac{n}{x} * \frac{m}{x}\)(下取整)
那么 \(f[k] = \sum_{k | d} \mu(d / k) * \frac{n}{d} * \frac{m}{d}\)
枚举i=d/k然后预处理\(\sum \mu\) 时间复杂度 \(O(q \sqrt n)\)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<bitset>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 5e4+10;
inline int read()
{
register int x = 0 , f = 0; register char c = getchar();
while(c < '0' || c > '9') f |= c == '-' , c = getchar();
while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
return f ? -x : x;
}
int tot;
int vis[N] , prime[N] , mu[N];
void Init(int maxn)
{
mu[1] = 1;
for(int i = 2 ; i <= maxn ; ++i)
{
if(!vis[i]) prime[++tot] = i , mu[i] = -1;
for(int j = 1 ; j <= tot && i * prime[j] <= maxn ; ++j)
{
vis[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
mu[i] += mu[i-1];
}
return ;
}
int calc(int n , int m , int k)
{
n /= k; m /= k; int ans = 0; if(n > m) swap(n , m);
for(int l = 1 , r ; l <= n ; l = r + 1)
{
r = min(n / (n / l) , m / (m / l));
ans += (mu[r] - mu[l-1]) * (n / l) * (m / l);
}
return ans;
}
void solve()
{
int a = read() , b = read() , c = read() , d = read() , k = read();
cout << calc(b , d , k) - calc(a - 1 , d , k) - calc(b , c - 1 , k) + calc(a - 1 , c - 1 , k) << '\n';
return ;
}
int main()
{
int T = read();
Init(5e4);
while(T--) solve();
// cout << calc(4 , 4 , 2) << '\n';
return 0;
}
P2257 YY的GCD
给定 N, MN,M,求 1 <= x && x <= n且 1 <= y && y <= m 且 gcd(x , y) 为质数的 (x,y) 有多少对。
n , m <= 1e7
和上一题类似,对着一个式子推啊推啊颓推 设n <= m
展开
考虑先枚举d
显然这东西可以预处理
\(\sum_{p \ belong \ prime \ \ \ p | d } \mu(d / p)\)
然后对其求个前缀和就和上一题一样了
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<bitset>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long LL;
const int N = 1e7+10;
inline int read()
{
register int x = 0 , f = 0; register char c = getchar();
while(c < '0' || c > '9') f |= c == '-' , c = getchar();
while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
return f ? -x : x;
}
int tot;
int vis[N] , prime[N] , mu[N];
LL f[N] , sum[N];
void Init(int maxn)
{
mu[1] = 1;
for(int i = 2 ; i <= maxn ; ++i)
{
if(!vis[i]) prime[++tot] = i , mu[i] = -1;
for(int j = 1 ; j <= tot && i * prime[j] <= maxn ; ++j)
{
vis[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1 ; i <= tot ; ++i)
for(int j = 1 ; j * prime[i] <= maxn ; ++j)
f[j * prime[i]] += mu[j];
for(int i = 1 ; i <= maxn ; ++i) sum[i] = sum[i-1] + f[i];
return ;
}
LL calc(int n , int m)
{
LL ans = 0; if(n > m) swap(n , m);
for(int l = 1 , r ; l <= n ; l = r + 1)
{
r = min(n / (n / l) , m / (m / l));
ans += (sum[r] - sum[l-1]) * (n / l) * (m / l);
}
return ans;
}
void solve()
{
int n = read() , m = read();
cout << calc(n , m) << '\n';
return ;
}
int main()
{
Init(1e7); int T = read();
while(T--) solve();
return 0;
}

浙公网安备 33010602011771号