タイトル
リンクタイトル:https://www.luogu.com.cn/problem/P2568
指定された整数\(N \) 、シーク\(1 \当量X、Y \ N当量\) と\(GCD(X、Y) \)に素数の数である\((X、Y)\ ) どのように多くのペア。
思考
列挙子素数を考える(P \)\、各素数のための\(P \)、\ ([1、N - ] \でX、Y \)と\(\ GCD(X、Y )= P \) のプログラム番号は([IN X、Y \ \ 1、\左\ lfloor \ FRAC {N} {P} \ \右rfloor] \) と\(\ GCD(X、Y )= 1 \) 番号スキーム。
考慮\(1 \当量X \当量 Y \当量のn \) と\(\ GCD(X、Y )= 1 \) 番号スキームを\(\和^ {\左 \ lfloor \ FRAC {n}は{ P} \右\ rfloor} _ {私は= 1} \ varphi(I)\) 、およびNOがない場合\(x \当量Y \)この制限は、プログラムナンバーである(2 \和は^ {\ \ \ lfloorを左\ {} {P N-FRAC} \右\ rfloor 1}} _ {I = \ varphi(I) - [IがJに= \ GCD(I、J)= 1。] \)。明らかに後者のみ\(I = J = \ 1 ) 場合、\(1 \当量X、Y \当量のn \) と\(\ GCD(X、Y )= P \) プログラムの数であります\(2 \ ^ {rfloor \右\ SUM \左\ lfloor \ {N-FRAC {P} 1}} _ {I = \ varphi(I)\)。
遮蔽\(1 \シムnは\)方法シークをプライミング\(\ varphi \) 、次いで(\ \ varphi \)は、接頭辞と、各素数のためにその\(P \)であることができる\(O(1 )\)の回答を求めています。
最終的な答えは
[\ sum_ {P \で\ operatorname \ {プライム}}((2 \ sum_ {i = 1} ^ {\左\ lfloor \ FRAC {N} {P} \ rfloor \右} \ varphi [I ]) - 1)\]
時間計算\(O(N)\)
コード
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=10000010;
int n,m,v[N],prime[N],phi[N];
ll ans,sum[N];
void find_prime(int n)
{
phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!v[i]) v[i]=i,prime[++m]=i,phi[i]=i-1;
for (int j=1;j<=m;j++)
{
if (prime[j]>v[i] || 1LL*prime[j]*i>n) break;
v[i*prime[j]]=prime[j];
if (i%prime[j]) phi[i*prime[j]]=phi[i]*(prime[j]-1);
else phi[i*prime[j]]=phi[i]*prime[j];
}
}
for (int i=1;i<=n;i++)
sum[i]=sum[i-1]+phi[i];
}
int main()
{
scanf("%d",&n);
find_prime(n);
for (int i=1;i<=m;i++)
ans+=2*sum[n/prime[i]]-1;
printf("%lld",ans);
return 0;
}