莫比烏斯反演1001 BZOJ 2818 莫比烏斯反演例題
阿新 • • 發佈:2019-02-12
題意:
給定整數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;
}