AcWing - 220 - 最大公约数 = 积性函数筛

https://www.acwing.com/problem/content/222/

求n以内gcd为质数的数对个数。

其实要是n和m不一样的话,貌似是要下面这样做的。也就是n和m不一样可能都得反演,下面这个是nlogn左右的,瓶颈在于给每个T刷上他的质因子p对应的mu[T/p]。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e7;
int Sum[MAXN + 5];

char mu[MAXN + 5];
int p[(MAXN) / 10 + 5], ptop;
bitset < MAXN + 5 > np;

void sieve(int n = MAXN) {
    np[1] = mu[1] = 1;
    for(int i = 2; i <= n; i++) {
        if(!np[i])
            p[++ptop] = i, mu[i] =  - 1;
        for(int j = 1, t; j <= ptop && (t = i * p[j]) <= n; j++) {
            np[t] = 1;
            if(i % p[j])
                mu[t] = -mu[i];
            else {
                mu[t] = 0;
                break;
            }
        }
    }
    for(int i = 1; i <= ptop; ++i) {
        for(int cnt = 1, x = p[i]; x <= n; x += p[i], ++cnt) {
            Sum[x] += mu[cnt];
        }
    }
    for(int i = 1; i <= n; ++i) {
        Sum[i] += Sum[i - 1];
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n;
    scanf("%d", &n);
    sieve(n);
    ll sum = 0;
    for(int l = 1, r; l <= n; l = r + 1) {
        r = n / (n / l);
        sum += 1ll * (n / l) * (n / l) * (Sum[r] - Sum[l - 1]);
    }
    printf("%lld\n", sum);
}

上网找了一个奇怪的线性筛,开眼界,什么都可以筛,根据最小质因子的个数进行分类讨论,这种解法是可以解决n和m不一样的问题的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e7;
int Sum[MAXN + 5];

char mu[MAXN + 5];
int p[(MAXN) / 10 + 5], ptop;
bitset < MAXN + 5 > np;

void sieve(int n = MAXN) {
    //Sum[T]表示T的所有质数因子p的mu[T/p]之和
    np[1] = mu[1] = 1;
    Sum[1] = 0;
    for(int i = 2; i <= n; i++) {
        if(!np[i]) {
            p[++ptop] = i, mu[i] =  - 1;
            Sum[i] = mu[1];
        }
        for(int j = 1, t; j <= ptop && (t = i * p[j]) <= n; j++) {
            np[t] = 1;
            if(i % p[j]) {
                mu[t] = -mu[i];
                Sum[t] = -Sum[i] + mu[i];
            } else {
                mu[t] = 0;
                //T有>=2个p
                //当T有2个p时,只有除掉p可能会有结果,此时为Sum[T]=mu[y]
                //当T有>=3个p时,结果都是0,此时也是Sum[T]=mu[y]
                Sum[t] = mu[i];
                break;
            }
        }
    }

    for(int i = 1; i <= n; ++i) {
        Sum[i] += Sum[i - 1];
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    int n;
    scanf("%d", &n);
    sieve(n);
    ll sum = 0;
    for(int l = 1, r; l <= n; l = r + 1) {
        r = n / (n / l);
        sum += 1ll * (n / l) * (n / l) * (Sum[r] - Sum[l - 1]);
    }
    printf("%lld\n", sum);
}

但是貌似因为n和m一样就可以简化。直接使用欧拉函数就完事了。

猜你喜欢

转载自www.cnblogs.com/Inko/p/11449603.html