题目链接:
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
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAX_N = 10000010;
int prime_cnt, prime[MAX_N];
bitset 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
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAX_N = 10000010;
bitset 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;
}