bzoj 2301 [HAOI2011]Problem b(莫比乌斯反演)
Description
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
Input
第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k
Output
共n行,每行一个整数表示满足要求的数对(x,y)的个数
Sample Input
2
2 5 1 5 1
1 5 1 5 2
2 5 1 5 1
1 5 1 5 2
Sample Output
14
3
3
HINT
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
【思路】
【代码】
1 #include<cstdio> 2 #include<iostream> 3 using namespace std; 4 5 typedef long long ll; 6 const int N = 500005; 7 8 int n; 9 ll su[N],sz,np[N],mu[N]; 10 11 void get_mu() 12 { 13 int i,j; 14 mu[1]=1; 15 for(int i=2;i<N;i++) { 16 if(!np[i]) { 17 su[++sz]=i; 18 mu[i]=-1; 19 } 20 for(int j=1;j<=sz&&i*su[j]<N;j++) { 21 np[su[j]*i]=1; 22 if(i%su[j]==0) mu[i*su[j]]=0; 23 else mu[i*su[j]]=-mu[i]; 24 } 25 } 26 for(int i=1;i<N;i++) 27 mu[i]+=mu[i-1]; 28 } 29 ll C(int m,int n,int k) 30 { 31 int i,last; ll res=0; 32 n/=k,m/=k; 33 for(i=1;i<=min(n,m);i=last+1) { 34 last=min(n/(n/i),m/(m/i)); 35 res+=(mu[last]-mu[i-1])*(m/i)*(n/i); 36 } 37 return res; 38 } 39 40 int main() 41 { 42 get_mu(); 43 int T,a,b,c,d,k; 44 scanf("%d",&T); 45 while(T--) { 46 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 47 printf("%d\n",C(b,d,k)-C(a-1,d,k)-C(b,c-1,k)+C(a-1,c-1,k)); 48 } 49 return 0; 50 }
posted on 2016-03-06 21:12 hahalidaxin 阅读(381) 评论(1) 编辑 收藏 举报