BZOJ 2818 Gcd(尤拉函式+質數篩選)
阿新 • • 發佈:2019-01-05
2818: Gcd
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 9108 Solved: 4066
[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(x,y)=prime[i];
gcd(x/prime[i],y/prime[i])=1;
求每個數的尤拉值再用字首和記錄該數前所有互質對數sum[i];
列舉1~n/prime[i]有多少對互質對數然後將x,y互換的情況加起來即可(注:gcd(1,1)出現兩次,所以要減1次)
#include<iostream> #include<stdio.h> #define ll long long using namespace std; const int maxn=1e7+7; bool mark[maxn]; ll prime[maxn],phi[maxn],sum[maxn]; void eular(int n){//線性篩選求尤拉值 int cnt=0; phi[1]=1; for(int i=2;i<=n;i++){ if(!mark[i]) prime[cnt++]=i,phi[i]=i-1; for(int j=0;j<cnt&&i*prime[j]<=n;j++){ mark[i*prime[j]]=1; if(i%prime[j])//互質 phi[i*prime[j]]=phi[i]*phi[prime[j]]; else{//不互質 phi[i*prime[j]]=phi[i]*prime[j];//原因:該質數已存在則不用乘(1-1/prime[j]); break;//防止重複增加時間 } } } } int main() { int n; scanf("%d",&n); eular(n); ll ans=0; for(int i=1;i<=n;i++)//i之前所有互質對數 sum[i]=sum[i-1]+phi[i]; for(int i=0;prime[i]&&prime[i]<=n;i++)//gcd(x/prime[i],y/prime[i])=1,x,y互換並減去(1,1)重複的情況 ans+=sum[n/prime[i]]*2-1; printf("%lld\n",ans); return 0; }