Gcd HYSBZ - 2818 (莫比烏斯反演)
阿新 • • 發佈:2018-11-15
Gcd
給定整數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
推導:
本題的本質就是
後面那個式子我們在莫比烏斯反演中已經見過很多了。
令
則有,進一步對F(x)進行推導得到:
對F(x)反演推回
則最初的式子就變成了
複雜度論證:
預處理mu[],F[],check[],以及最終處理ans都是O(1)的複雜度
主要是處理f(x)的複雜度的。
對於f(x)的處理,我們採用這樣一段程式碼:
for(int i=1;i<=n;i++)
{
if(check[i])continue;
for(int j=i;j<=n;j+=i)
{
f[i]+=1ll*mu[j/i]*F[j];
}
}
其中的i就是x,j就是kx,可以看出來這個式子的複雜度是
這個式子求和較難,不如將它放大一點,成:
這個複雜度沒有問題
AC程式碼:
#include<cstdio> #include<iostream> #include<cstring> using namespace std; const int MAXN=1e7; bool check[MAXN+10]; int prime[MAXN+10]; int mu[MAXN+10]; void Moblus() { memset(check,false,sizeof(check)); mu[1] = 1; check[1]=true; int tot = 0; for(int i = 2; i <= MAXN; i++) { if( !check[i] ){ prime[tot++] = i; mu[i] = -1; } for(int j = 0; j < tot; j++) { if(i * prime[j] > MAXN) break; check[i * prime[j]] = true; if( i % prime[j] == 0){ mu[i * prime[j]] = 0; break; }else{ mu[i * prime[j]] = -mu[i]; } } } } long long F[MAXN+10],f[MAXN+10]; int main() { Moblus(); int n; scanf("%d",&n); for(int i=1;i<=n;i++) F[i]=1ll*(n/i)*(n/i); for(int i=1;i<=n;i++) { if(check[i])continue; for(int j=i;j<=n;j+=i) { f[i]+=1ll*mu[j/i]*F[j]; } } long long ans=0; for(int i=1;i<=n;i++)if(!check[i]) ans+=1ll*f[i]; printf("%lld\n",ans); }