BZOJ2818: Gcd
2818: Gcd
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 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; }