Gym - 101982B Coprime Integers (莫比乌斯裸题)

原题地址:http://codeforces.com/gym/101982
参考博客:https://blog.csdn.net/jk_chen_acmer/article/details/82016719

这篇博客主要是讲述一些莫比乌斯的知识。
关于莫比乌斯函数
莫比乌斯函数其实就只是一个系数,它的取值如下:

1)莫比乌斯函数μ(n)的定义域是N
2) μ ( 1 ) = 1 μ(1)=1 μ(1)=1
3)当 n n n存在平方因子时, μ ( n ) = 0 μ(n)=0 μ(n)=0
4)当 n n n是素数或奇数个不同素数之积时, μ ( n ) = − 1 μ(n)=-1 μ(n)=1
5)当 n n n是偶数个不同素数之积时, μ ( n ) = 1 μ(n)=1 μ(n)=1
在这里插入图片描述
关于莫比乌斯反演
主要有两种形式:

Gym - 101982B Coprime Integers (莫比乌斯裸题)_第1张图片
上面的被称为约数反演,下面的被称为倍数反演。
作用:它是两个函数互相转换时的一大利器。
所以在某些情况下当 f ( d ) f(d) f(d)不好处理而 F ( n ) F(n) F(n)比较好求时可以考虑求出 F ( n ) F(n) F(n)的值再反演给 f ( d ) f(d) f(d)

对于这道题
具体参考上面的参考链接。


#include 
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e7 + 5;
const int mod = 1e9 + 7;
bool isprime[maxn];
int prime[maxn];
int sum[maxn], mu[maxn];
int pcnt;
void mobi(int N) {
     
    memset(isprime, true, sizeof(isprime));
    mu[1] = 1;
    for (int i = 2; i < N; i++) {
     
        if (isprime[i]) {
     
            prime[++pcnt] = i;
            mu[i] = -1;
        }
        for (int j = 1;  i * prime[j] < N; j++) {
     
            isprime[i * prime[j]] = false;
            if (i % prime[j] == 0) {
     
                mu[i * prime[j]] = 0;
                break;
            } else mu[i * prime[j]] = -mu[i];
        }
    }
    for (int i = 1; i < N; i++) {
     //前缀和预处理
        sum[i] = mu[i] + sum[i - 1];
    }
}
ll a, b, c, d;
ll solve(ll n, ll m) {
     
    if (n > m) swap(n, m);
    ll ans = 0;
    for (ll i = 1, last; i <= n; i = last + 1) {
     //处理了前缀和之后分块处理
        last = min(n / (n / i), m / (m / i));
        ans += (sum[last] - sum[i - 1]) * (n / i) * (m / i);
    }
    return ans;
}
int main() {
     
    mobi(1e7 + 1);
    scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
    ll ans = solve(b, d) - solve(a - 1, d) - solve(b, c - 1) + solve(a - 1, c - 1);//像二维前缀和一样容斥
    printf("%lld\n", ans);
    return 0;
}




你可能感兴趣的:(ACM_数论)