BZOJ2301 HAOI2011 problem b 莫比乌斯反演+容斥原理
题意:N组询问,每次给出a b c d k,求满足a≤x≤b,c≤y≤d且gcd(x,y)=k的数对(x,y)的数量。
题解:
设fA,B,k表示1≤x≤A,1≤y≤B内合法数对的数量,那么答案就是fb,d-fa,d-fb,c+fa,c。设FA,B,i=i|gcd(x,y)(i=tk,1≤x≤A,1≤y≤B)的数对数量,显然\[{F_{A,B,i}} = \left\lfloor {\frac{A}{i}} \right\rfloor \left\lfloor {\frac{B}{i}} \right\rfloor = \sum\limits_{k|i} {{f_{A,B,k}}} \]
反演之后得到\[{f_{A,B,k}} = \sum\limits_{k|i} {\mu (\frac{i}{k}){F_{A,B,i}}} \]
然后进行函数分块即可
#include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define ll long long const int MAXN=60000+2; int N,a,b,c,d,K,mu[MAXN],prime[MAXN]; bool flag[MAXN]; void Moebius(int N,int *mu){ mu[1]=1; for(int i=2,j=0;i<=N;i++){ if(!flag[i]) prime[++j]=i,mu[i]=-1; for(int k=1;k<=j && i*prime[k]<=N;k++){ flag[i*prime[k]]=1; if(i%prime[k]==0){ mu[i*prime[k]]=0; break; } mu[i*prime[k]]=-mu[i]; } } for(int i=2;i<=N;i++) mu[i]+=mu[i-1]; } ll Solve(int N,int M,int K){ ll ret=0; N/=K,M/=K; for(int i=1,j;i<=M && i<=N;i=j+1){ j=min(N/(N/i),M/(M/i)); ret+=(ll)(mu[j]-mu[i-1])*(N/i)*(M/i); } return ret; } int main(){ Moebius(MAXN,mu); cin >> N; while(N--){ scanf("%d %d %d %d %d",&a,&b,&c,&d,&K); printf("%lld\n",Solve(b,d,K)-Solve(a-1,d,K)-Solve(b,c-1,K)+Solve(a-1,c-1,K)); } return 0; }