BZOJ2818: Gcd

2818: Gcd

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 6264  Solved: 2772
[Submit][Status][Discuss]

Description

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.

 

Input

一个整数N

Output

如题

Sample Input

4

Sample Output

4

HINT

 

hint

对于样例(2,2),(2,4),(3,3),(4,2)


1<=N<=10^7

 

思路{

  莫比乌斯反演板子题,写完发现正解直接欧拉函数就可以了QAQ T_T.

  Ans=(k)∑(i=1) (F(n,pi))

  其中k<=n的质数个数,pi为第i个质数.

  F(i,j)=∑(1<=a,b<=i)[GCD(a,b)=j]

  套路:f(i,j)=∑(1<=a,b<=i)[GCD(a,b)|j];

  F(i,j)=∑(j|d) μ( d/j ) * ( (i/d)^2 ).

  所以Ans=(k)∑(i=1) ( ∑(pi|d) μ( d/pi ) * ( (n/d)^2 ) )

  把d/pi变成for枚举

  Ans=(k)∑(i=1) ( (n/pi)∑(d=1) μ( d ) * { [ (n/pi)/d ] )^2 } )

  设G(x)=(x)∑(i=1) μ(i)*( (x/i)^2 )

  Ans=(k)∑(i=1)G(n/pi)

  G是可以数论分块sqrt(n)的求.

  对外面这层枚举质数个数,打表发现有600000左右.直接枚举不行.

  那么记录一个前缀和记录一段区间多少个质数,这一段贡献相等.

  那么再在外面套一个数论分块就可以了.

}

#include<bits/stdc++.h>
#define RG register
#define il inline
#define db double
#define LL long long
#define N 10000001
using namespace std;
bool vis[N];int p[N],mu[N],sum[N],n;
void make(){
  mu[1]=1;vis[1]=true;
  for(RG int i=2;i<N;++i){
    if(!vis[i])mu[i]=-1,p[++p[0]]=i;
    for(RG int j=1;j<=p[0]&&p[j]*i<N;++j){
      vis[i*p[j]]=true;
      if(i%p[j])mu[i*p[j]]=-mu[i];
      else {
    mu[i*p[j]]=0;break;
      }
    }
  }
  for(RG int i=1;i<N;++i)mu[i]+=mu[i-1],sum[i]=sum[i-1]+(vis[i]?0:1);
}
LL calc(LL num){
  LL sum(0);
  for(int l=1,r;l<=num;l=r+1){
    r=num/(num/l);
    LL tmp=(LL)num/l;tmp=(LL)tmp*tmp;
    sum+=(mu[r]-mu[l-1])*tmp;
  }return sum;
}
void work(){
  LL Ans(0);
  for(int l=1,r;l<=n;l=r+1){
    r=n/(n/l);
    if(sum[r]==sum[l-1])continue;
    Ans+=(LL)(sum[r]-sum[l-1])*calc(n/l);
  }cout<<Ans;
}
int main(){
  make();
  scanf("%d",&n);
  work();
  return 0;
}
posted @ 2017-09-05 10:01  QYP_2002  阅读(158)  评论(0编辑  收藏  举报