BZOJ2820:YY的GCD

Sol

推导:(n<m,p为质数)
(ans=sum_psum_{i=1}^{frac{n}{p}}mu(i)frac{n}{pi}frac{m}{pi})
(=sum_{k=1}^{n}frac{n}{k}frac{m}{k}sum_{p|k}mu(frac{k}{p}))
(sum_{p|k}mu(frac{k}{p}))可以暴力预处理,也可以在筛的时候计算出

暴力求

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Zsydalao 666
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(1e7 + 1);
 
IL ll Read(){
    char c = '%'; ll x = 0, z = 1;
    for(; c > '9' || c < '0'; c = getchar()) if(c == '-') z = -1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
    return x * z;
}
 
int prime[_], num, mu[_], f[_];
bool isprime[_];

IL void Prepare(){
    isprime[1] = 1; mu[1] = 1;
    for(RG int i = 2; i < _; ++i){
        if(!isprime[i]) prime[++num] = i, mu[i] = -1;
        for(RG int j = 1; j <= num && i * prime[j] < _; ++j){
            isprime[i * prime[j]] = 1;
            if(i % prime[j])  mu[i * prime[j]] = -mu[i];
            else{  mu[i * prime[j]] = 0; break;  }
        }
    }
    for(RG int i = 1; i < _; ++i)
        for(RG int j = 1; j <= num && i * prime[j] < _; ++j)
            f[i * prime[j]] += mu[i];
    for(RG int i = 1; i < _; ++i) f[i] += f[i - 1];
}
 
int main(RG int argc, RG char *argv[]){
    Prepare();
    for(RG int T = Read(); T; --T){
        RG ll n = Read(), m = Read(), ans = 0;
        if(n > m) swap(n, m);
        for(RG ll k = 1, j; k <= n; k = j + 1){
            j = min(n / (n / k), m / (m / k));
            ans += (n / k) * (m / k) * (f[j] - f[k - 1]);
        }
        printf("%lld
", ans);
    }
    return 0;
}

筛的时候处理

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Zsydalao 666
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(1e7 + 1);
 
IL ll Read(){
    char c = '%'; ll x = 0, z = 1;
    for(; c > '9' || c < '0'; c = getchar()) if(c == '-') z = -1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
    return x * z;
}
 
int prime[_], num, mu[_], f[_];
bool isprime[_];

IL void Prepare(){
	isprime[1] = 1; mu[1] = 1;
	for(RG int i = 2; i < _; ++i){
		if(!isprime[i]) prime[++num] = i, mu[i] = -1, f[i] = 1;
		for(RG int j = 1; j <= num && i * prime[j] < _; ++j){
			isprime[i * prime[j]] = 1;
			if(i % prime[j])  mu[i * prime[j]] = -mu[i], f[i * prime[j]] = mu[i] - f[i];
			else{  mu[i * prime[j]] = 0; f[i * prime[j]] = mu[i]; break;  }
		}
	}
	for(RG int i = 1; i < _; ++i) f[i] += f[i - 1];
}
 
int main(RG int argc, RG char *argv[]){
	Prepare();
	for(RG int T = Read(); T; --T){
		RG ll n = Read(), m = Read(), ans = 0;
		if(n > m) swap(n, m);
		for(RG ll k = 1, j; k <= n; k = j + 1){
			j = min(n / (n / k), m / (m / k));
			ans += (n / k) * (m / k) * (f[j] - f[k - 1]);
		}
		printf("%lld
", ans);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/cjoieryl/p/8288744.html