1. 程式人生 > >莫比烏斯反演1001 BZOJ 2818 莫比烏斯反演例題

莫比烏斯反演1001 BZOJ 2818 莫比烏斯反演例題

題意:
給定整數N,求1<=x,y<=N且Gcd(x,y)為素數的
數對(x,y)有多少對.
思路:
可以尤拉函式解,比較簡單,為了練習一下莫比烏斯反演
很多解釋都在程式碼裡面了,這道題基本上就是例題…

/*

*/
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector> #include<map> #include<set> using namespace std; #define lowbit(x) (x&(-x)) typedef long long LL; const int maxn = 100005; const int inf=(1<<28)-1; #define maxp 10000005 bool notprimes[maxp]; int primes[maxp]; int mu[maxp]; LL Sum[maxp],Pre[maxp]; void get_mu() { memset
(notprimes,false,sizeof(notprimes)); primes[0]=0; mu[1]=1; for(int i=2;i<maxp;++i) { if(!notprimes[i]) { primes[++primes[0]]=i; Sum[i]=1; mu[i]=-1; } for(int j=1;j<=primes[0];++j) { if((LL)primes[j]*i>=maxp) break
; notprimes[i*primes[j]]=true; if(i%primes[j]) { mu[i*primes[j]]=-mu[i]; Sum[i*primes[j]]=mu[i]-Sum[i]; //T=i的時候,Sum[T]=Sum[i] //當為T再加上一個與之前不重複的素因子成為T1 //Sum[T1]=∑(p|T1,mu[T1/p])=∑(p|T,-mu[T/p]) + mu[T] //之所以取負數,因為mu[T],對T進行素因子分解以後都是互異素數時 //mu[T]=(-1)^k k是素數的個數,素數加了一個,所以取反 //再加上多加一個素數後會多一個mu[T]就是Sum[T1] } else { mu[i*primes[j]]=0; Sum[i*primes[j]]=mu[i]; //這裡分兩種情況 T=i T1=i*primes[j] //1. T=p1 * p2 * p3 * p4 * ... pk //此時∑(p|T1,mu[T1/p]),p=primes[j]的時候mu[T]=Sum[T1]=(-1)^k //2. T=p1^2 * p2 * p3 * p4 * ... pk //此時不論p是什麼,對T1/p就行質因子分解後都不會存在所有素數互異的情況 break;//代表i不是素數,mu[i*primes[j]]必然是0 } } } } int main() { get_mu(); Pre[0]=0; for(int i=1;i<maxp;++i) Pre[i]=Pre[i-1]+Sum[i]; /*for(int i=1;i<=4;++i) printf("%d ",Sum[i]);printf("\n");*/ int n; scanf("%d",&n); LL Ans=0; int last; for(int i=1;i<=n;i=last+1) { last=n/(n/i); //這裡是莫比烏斯反演的題目裡經常用到的分塊加速 //因為很多情況下我們都會用到下面這個式子 //但是我們發現有些連續的數(n/i)都是一樣的 //我們就可以通過字首來把它們一起求出來 //假設n==9 //i=1->i=2->i=3->i=4->i=5->i=10 //因為5~9的n/i==1所以直接一起求出來 Ans+=(LL)(n/i)*(n/i)*(Pre[last]-Pre[i-1]); } printf("%lld\n",Ans); return 0; }