BZOJ 2818 Gcd(gcd(x,y)为素数/欧拉函数/莫比乌斯反演)

来源:互联网 发布:数控车梯形螺纹g92编程 编辑:程序博客网 时间:2024/05/01 03:36

题目链接:
BZOJ 2818 Gcd
题意:
x[1,N],y[1,N]gcd(x,y)=(x,y)
分析:
对于一个素数p,如果gcd(x,y)=p,那么相当于x[1,Np],y[1,Ny](x,y)的对数,又因为是有序对,需要乘以2,那么就是Npi=12ϕ(i),其中ϕ(i)i的欧拉函数,所以需要记录欧拉函数的前缀和,但是其实这样是少算了的,因为gcd(p,p)=p就没算到。所以对于每个素数都要额外+1

#include <stdio.h>#include <cstring>#include <algorithm>#include <bitset>#include <cmath>using namespace std;typedef long long ll;const int MAX_N = 10000010;int prime_cnt, prime[MAX_N];bitset<MAX_N> bs;ll phi[MAX_N], sum[MAX_N];void GetPhi(){    bs.set();    prime_cnt = 0;    for(int i = 2; i < MAX_N; i++) {        if(bs[i]) {            prime[prime_cnt++] = i;            phi[i] = i - 1;        }        for(int j = 0; j < prime_cnt && i * prime[j] < MAX_N; j++) {            bs[i * prime[j]] = 0;            if(i % prime[j] == 0) {                phi[i * prime[j]] = prime[j] * phi[i];                break;            }else {                phi[i * prime[j]] = (prime[j] - 1) * phi[i];            }        }    }    for(int i = 1; i < MAX_N; i++){        sum[i] = sum[i - 1] + 2 * phi[i];    }}ll solve(int n){    ll ans = 0;    for(int i = 0; i < prime_cnt && prime[i] <= n; i++){        ans += sum[n / prime[i]] + 1;    }    return ans;}int main(){    GetPhi();    int n;     while(~scanf("%d", &n)){        printf("%lld\n", solve(n));    }    return 0;}

也可以是使用莫比乌斯反演。参考博客:http://blog.csdn.net/acdreamers/article/details/8542292

#include <stdio.h>#include <cstring>#include <algorithm>#include <string>#include <cmath>#include <bitset>#include <iostream>using namespace std;typedef long long ll;const int MAX_N = 10000010;bitset<MAX_N> bs;int prime_cnt, prime[MAX_N / 100 * 7];int mu[MAX_N], g[MAX_N];ll sum[MAX_N];void init(){    bs.set();    prime_cnt = 0;    mu[1] = 1;    for(int i = 2; i < MAX_N; ++i) {        if(bs[i]) {            prime[prime_cnt++] = i;            mu[i] = -1;            g[i] = 1;        }        for(int j = 0; j < prime_cnt && i * prime[j] < MAX_N; ++j ){            bs[i * prime[j]] = 0;            if(i % prime[j]){                mu[i * prime[j]] = -mu[i];                g[i * prime[j]] = mu[i] - g[i];            }else {                mu[i * prime[j]] = 0;                g[i * prime[j]] = mu[i];                break;            }        }    }    sum[0] = 0;    for(int i = 1; i < MAX_N; ++i) {        sum[i] = sum[i - 1] + g[i];    }}ll solve(int n, int m){    int top = min(n, m), last;    ll ans = 0;    for(int i = 1; i <= top; i = last + 1) {        last = min(n / (n / i), m / (m / i));        ans += (ll)n / i * (m / i) * (sum[last] - sum[i - 1]);    }    return ans;}int main(){    init();    int  n;    while(~scanf("%d", &n)){        printf("%lld\n", solve(n, n));    }    return 0;}
0 0
原创粉丝点击