题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2818
思路:
求1<=x,y<=N且Gcd(x,y)为素数 (i)的数对(x,y)有多少对.
可以写成
求1<=x,y<=N/ i 且Gcd(x,y)为 1 的数对(x,y)有多少对.
这就成了x,y互质,于是 欧拉(y)就求出了与y互质的x个数,即(x,y)对数,
i当然小于n,枚举每个i,即n/i,向下取整,把所有对应欧拉(y)求出,这里用前缀和处理即可。
用线性筛数组改成 ll 就过了,但时间比普通筛要长啊~~
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int MAXN = 10000000;
bool check[MAXN + 10];
ll phi[MAXN + 10],prime[MAXN + 10],sum[MAXN+10];
int tot;
void phi_and_prime_table(int N){
memset(check, false, sizeof(check));
phi[1] = 1;
tot = 0;
for (int i = 2; i <= N; i++){
if (!check[i]){
prime[tot++] = i;
phi[i] = i - 1;
}
for (int j = 0; j < tot; j++){
if (i * prime[j] > N)
break;
check[i * prime[j]] = true;
if (i % prime[j] == 0){
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
else
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
return ;
}
int main(){
int n;
ll ans=0;
scanf("%d",&n);
phi_and_prime_table(n);
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+phi[i];
for(int i=0;i<tot;i++)
ans+=sum[n/prime[i]]*2-1;
printf("%lld\n",ans);
return 0;
}
普通筛:
#include<iostream>
#include<cstdio>
#define ll long long
#define N 10000005
using namespace std;
ll ans,sum[N];
int n,p,tot;
int phi[N],pri[1000005];
bool mark[N];
void getphi(){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!mark[i]){phi[i]=i-1;pri[++tot]=i;}
for(int j=1;j<=tot;j++){
int x=pri[j];
if(i*x>n)break;
mark[i*x]=1;
if(i%x==0){phi[i*x]=phi[i]*x;break;}
else phi[i*x]=phi[i]*phi[x];
}
}
}
int main(){
scanf("%d",&n);
getphi();
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+phi[i];
for(int i=1;i<=tot;i++)
ans+=sum[n/pri[i]]*2-1;
printf("%lld",ans);
return 0;
}