# [莫比乌斯反演+容斥+分块求和] BZOJ2301: [HAOI2011]Problem b

### 题意

1≤T,a,b,c,d,k≤50000

### 题解

f(i)$f(i)$ 表示满足gcd(x,y)等于i的有序数对(x,y)的个数。(1<=x<=n且1<=y<=m)

F(i)$F(i)$很好求，只有x和y都是i的倍数即可，所以F(i)=nimi$F(i)=\lfloor \frac{n}{i} \rfloor\lfloor \frac{m}{i} \rfloor$

F(i)=i|df(d)f(i)=i|dμ(di)F(d)=i|dμ(di)ndmd

    if(n>m) swap(n,m);
int res=0;
for(int d=1,nxt=0;d<=n;d=nxt+1){
nxt=min(n/(n/d),m/(m/d));
res+=(n/d)*(m/d)*(sum_mu[nxt]-sum_mu[d-1]);
} 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000005, N=1000000;
int _test,K,p[maxn],mu[maxn],sum_mu[maxn];
bool vis[maxn];
void get_mu(){
memset(vis,1,sizeof(vis));
mu[1]=1;
for(int i=2;i<=N;i++){
if(vis[i]) p[++p[0]]=i, mu[i]=-1;
for(int j=1;j<=p[0]&&i*p[j]<=N;j++){
vis[i*p[j]]=false;
if(i%p[j]==0){ mu[i*p[j]]=0; break; }
mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=N;i++) sum_mu[i]=sum_mu[i-1]+mu[i];
}
int get(int n,int m){
n/=K; m/=K;
if(n>m) swap(n,m);
int res=0;
for(int d=1,nxt=0;d<=n;d=nxt+1){
nxt=min(n/(n/d),m/(m/d));
res+=(n/d)*(m/d)*(sum_mu[nxt]-sum_mu[d-1]);
}
return res;
}
int main(){
freopen("bzoj2301.in","r",stdin);
freopen("bzoj2301.out","w",stdout);
get_mu();
scanf("%d",&_test);
while(_test--){
int a,b,c,d;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&K);
printf("%d\n",get(b,d)-get(a-1,d)-get(b,c-1)+get(a-1,c-1));
}
return 0;
}

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客