莫比乌斯入门请耐心往下看:
OK.现在可以开始刷题了。
莫比乌斯反演 HDU 1695 GCD
从区间[1, b]和[1,d]中分别选一个x, y,使得gcd(x, y) == k, 求满足条件的xy的对数(不区分xy的顺序)
分析:转换成求[1,b/k],[1,d/k]中gcd(x,y)==1的(x,y)对数.需要知道下面这个定理
然后把这个定理换成代码就好
#include
#include
#include
#include
#include
#include
#include
#include
求莫比乌斯函数模板如下:两种求法,第一种更快,但代码量大。第二种代码少,但耗时久。
const int MAXN = 100000;
//线性筛法求莫比乌斯函数
bool check[MAXN+10];
int prime[MAXN+10];
int mu[MAXN+10];
void Moblus()
{
memset(check,false,sizeof(check));
mu[1] = 1;
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];
}
}
}
}
/*int mu[MAXN+10]={0};
void getMu(){ //n*logn 递推筛法
for(int i=1; i<=MAXN; i++)
{
int target = i==1?1:0;
int delta = target - mu[i];
mu[i]=delta;
for(int j=i*2; j<=MAXN; j+=i)
mu[j]+=delta;
}
}*/
1 2 3 4 5 6 7 8 9 10 11 12 13
0 -1 -1 0 -1 1 -1 0 0 1 -1 0 -1
BZOJ 2301 Problem b
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=37166
对于给出的 n 个询问, 每次求有多少个数对(x,y), 满足 a≤x≤b, c≤y≤d, 且 gcd(x,y) = k,
gcd(x,y)函数为 x 和 y 的最大公约数。
1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
数据量大,需要分段优化
#include
#include
#include
#define sf(n) scanf("%d", &n)
typedef long long LL;
using namespace std;
const int MAXN = 50000+5;
bool check[MAXN+10];
int prime[MAXN+10],mu[MAXN+10],sum[MAXN+10];
void Moblus()
{
memset(check,false,sizeof(check));
mu[1] = 1;
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];
}
}
}
LL calc(int n,int m)//计算[1,n]和[1,m]中gcd==1的数对。(3,2),(2,3)算两个
{
LL ret=0;
if(n>m) swap(n,m);
for(int i=1,next=0;i<=n;i=next+1){
int d1=n/i,d2=m/i;
int next1=n/d1,next2=m/d2;
next=min(next1,next2);
ret+=(LL)(sum[next]-sum[i-1])*d1*d2;
}
return ret;
}
int main()
{
Moblus();
for(int i=1;i<=MAXN;i++) sum[i]=sum[i-1]+mu[i];
int a,b,c,d,k,T;
for(sf(T);T--;){
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
LL ans=calc(b/k,d/k)-calc((a-1)/k,d/k)-calc((c-1)/k,b/k)+calc((a-1)/k,(c-1)/k);
printf("%lld\n",ans);
}
return 0;
}
SPOJ 7001. Visible Lattice Points(莫比乌斯反演)SPOJ VLATTICE
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=37193
求一个n*n*n的晶体,有多少点可以在(0,0,0)处可以直接看到。
也就是不是有点在它们之间,即它们gcd(x,y,z)==1. 加上特例:3个轴+3个平面
/*
这题是求(0,0,0)~(N,N,N)中gcd(a,b,c)=1的点的个数
显然就是莫比乌斯反演的板题了...很容易就能得出F(1) =sigma(miu(d)*(n/d)*(n/d)*(n/d))
但这求出来的是(1,1,1)~(N,N,N)中的点的个数...还要加上含0的三个平面内的点...
因为对称...所以直接加上二维上的整点数*3
最后再加上(0,0,1),(1,0,0),(0,1,0)三个点...就OK了...
*/
#include
#include
#include
#include
#include
#include
#include
#include