您的位置:首页 > 其它

莫比乌斯反演1001 BZOJ 2818 莫比乌斯反演例题

2016-08-01 19:56 323 查看
题意:

给定整数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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: