2818: Gcd
2818: Gcd
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4488 Solved: 1984
[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
【题解】:
gcd(a,b)=p 则 gcd(a/p,b/p)=1;
设 a<=b 则gcd(a,b)=phi[b](与b互质的个数)
所以只需要枚举每一个素数,每一个数(这里可以用n的前缀和来维护,记为sum[n])求解出ans=Σf[n/prime[i]]*2-1(考虑a>b,并减去(1,1)之类的值)
【代码】:
1
#include<ctime> #include<cstdio> #include<cstdlib> #include<iostream> using namespace std; typedef long long ll; const int N=1e7+10; bool check[N]; int n,tot,prime[N/3]; int phi[N]; ll ans,f[N]; void sieve(){ f[1]=phi[1]=1; for(int i=2;i<=n;i++){ if(!check[i]) prime[++tot]=i,phi[i]=i-1; for(int j=1;j<=tot&&i*prime[j]<=n;j++){ check[i*prime[j]]=1; if(!(i%prime[j])){phi[i*prime[j]]=phi[i]*prime[j];break;} else phi[i*prime[j]]=phi[i]*(prime[j]-1); } } for(int i=2;i<=n;i++) f[i]=f[i-1]+(phi[i]<<1); } int main(){ scanf("%d",&n); sieve(); for(int i=1;i<=tot;i++) ans+=f[n/prime[i]]; printf("%lld\n",ans); // printf("\n%lf.sec\n",(double)clock()/CLOCKS_PER_SEC); return 0; }
2
//#include<ctime> #include<cstdio> #include<iostream> #ifdef WIN32 #define LL "%I64d" #else #define LL "%lld" #endif using namespace std; typedef long long ll; const int M=1e7+5; int n,m,T;ll ans,sum[M]; int tot,prime[M/3],mu[M];bool check[M]; void sieve(){ mu[1]=1; for(int i=2;i<=n;i++){ if(!check[i]) prime[++tot]=i,mu[i]=-1; for(int j=1;j<=tot&&i*prime[j]<=n;j++){ check[i*prime[j]]=1; if(!(i%prime[j])){mu[i*prime[j]]=0;break;} else mu[i*prime[j]]=-mu[i]; } } for(int i=1;i<=n;i++) sum[i]=sum[i-1]+mu[i]; } inline ll s2(int x){return 1LL*x*x;} inline ll solve(int n){ ll ans=0; for(int i=1,pos;i<=n;i=pos+1){ pos=n/(n/i); ans+=s2(n/i)*(sum[pos]-sum[i-1]); } return ans; } int main(){ scanf("%d",&n);sieve(); for(int i=1;i<=tot;i++) ans+=solve(n/prime[i]); printf(LL"\n",ans); // printf("\n%.3lf.sec",(double)clock()/CLOCKS_PER_SEC); return 0; }