BZOJ2301: [HAOI2011]Problem b

2301: [HAOI2011]Problem b

Time Limit: 50 Sec  Memory Limit: 256 MB
Submit: 5876  Solved: 2675
[Submit][Status][Discuss]

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

思路{

  n/k,m/k,转化为gcd(i,j)==1,

  那么直接上套路莫比乌斯反演+数论分块就可以了,

  再区间加一加,减一减就可以了.

}

 

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define il inline
#define N 50200
#define LL long long
using namespace std;
bool vis[N];
LL p[N],mu[N];
void pre(){
  mu[1]=1;
  for(int i=2;i<N;++i){
    if(!vis[i])mu[i]=-1,p[++p[0]]=i;
    for(int j=1;j<=p[0]&&p[j]*i<N;++j){
      vis[i*p[j]]=true;
      if(i%p[j])mu[i*p[j]]=-mu[i];
      else {
    mu[i*p[j]]=0;
    break;
      }
    }
  }for(int i=2;i<N;++i)mu[i]+=mu[i-1];
}
LL cal(int n,int m){
  LL ans=0;
  if(n>m)swap(n,m);
  for(int l=1,r;l<=n;l=r+1){
    r=min(n/(n/l),m/(m/l));
    ans+=(mu[r]-mu[l-1])*(n/l)*(m/l);
  }return ans;
}
int main(){
  int T;scanf("%d",&T);pre();
  while(T--){
    int a,b,c,d,k;
    scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    a--,c--;a/=k,b/=k,c/=k,d/=k;
    cout<<cal(b,d)+cal(a,c)-cal(a,d)-cal(c,b)<<"\n";
  }return 0;
}

 

posted @ 2017-09-05 00:02  QYP_2002  阅读(...)  评论(...编辑  收藏