1. 程式人生 > >bzoj 2301 [HAOI2011]Problem b (莫比烏斯反演)

bzoj 2301 [HAOI2011]Problem b (莫比烏斯反演)

題目大意:已知x\in [a,b],y\in [c,d],求gcd(x,y)為k的有序數對數量 a,b,c,d,k及詢問數<=50000

yy的gcd好做一些吧

轉化題目,直接求解比較困難,利用容斥原理,問題轉化為求$ans(b,d)-ans(a-1,d)-ans(b,c-1)+ans(a-1,c-1)$

求$\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)==k]$

化簡$\sum_{i=1}^{\left \lfloor \frac{n}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{m}{k} \right \rfloor}[gcd(i,j)==1]$

套路變形$\sum_{d=1}^{\left \lfloor \frac{n}{k} \right \rfloor}\left \lfloor \frac{n}{kd} \right \rfloor \cdot \left \lfloor \frac{m}{kd} \right \rfloor\cdot \mu(d)$

預處理$\mu(d)$的字首和,再整除分塊的思想求解即可

與yy的gcd那道題不同,整除分塊的部分有一些細節需要思考

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4
#define N 50100 5 #define maxn 50000 6 #define ll long long 7 using namespace std; 8 9 int T,a,b,c,d,K,cnt; 10 int use[N],pr[N],mu[N],pmu[N]; 11 void Pre() 12 { 13 mu[1]=1; 14 for(int i=2;i<=maxn;i++) 15 { 16 if(!use[i]) pr[++cnt]=i,mu[i]=-1; 17 for(int j=1
;j<=cnt&&i*pr[j]<=maxn;j++){ 18 use[i*pr[j]]=1; 19 if(i%pr[j]==0){ 20 mu[i*pr[j]]=0; 21 break; 22 }else{ 23 mu[i*pr[j]]=-mu[i]; 24 } 25 } 26 } 27 for(int i=1;i<=maxn;i++) 28 pmu[i]=pmu[i-1]+mu[i]; 29 } 30 ll solve(int n,int m) 31 { 32 if(n>m) swap(n,m); 33 ll ans=0;int nd,md; 34 for(int i=1,la,mi=min(n/K,m/K);i<=mi;i=la+1) 35 { 36 nd=n/K,md=m/K; 37 la=min(nd/(nd/i),md/(md/i)); 38 ans+=1ll*(n/(K*i))*(m/(K*i))*(pmu[la]-pmu[i-1]); 39 }return ans; 40 } 41 int main() 42 { 43 scanf("%d",&T); 44 Pre(); 45 for(int t=1;t<=T;t++) 46 { 47 scanf("%d%d%d%d%d",&a,&b,&c,&d,&K); 48 printf("%lld\n",solve(b,d)-solve(a-1,d)-solve(b,c-1)+solve(a-1,c-1)); 49 } 50 return 0; 51 }