山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

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

Sample Output

14

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  阅读(375)  评论(1编辑  收藏  举报