zboj 2301 Problem b (莫比乌斯反演)

来源:互联网 发布:杭州sql培训班 编辑:程序博客网 时间:2024/06/05 17:07

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




#include <cstdio>  #include <cstring>  #include <algorithm>  using namespace std;  int const MAX = 50005;  int p[MAX], mob[MAX], sum[MAX];  bool prime[MAX];  int a, b, c, d, k;     void Mobius()  {      int pnum = 0;      memset(prime, true, sizeof(prime));      memset(sum, 0, sizeof(sum));      mob[1] = 1;      sum[1] = 1;      for(int i = 2; i < MAX; i++)      {          if(prime[i])          {              p[pnum ++] = i;              mob[i] = -1;          }          for(int j = 0; j < pnum && i * p[j] < MAX; j++)          {              prime[i * p[j]] = false;              if(i % p[j] == 0)              {                  mob[i * p[j]] = 0;                  break;              }              mob[i * p[j]] = -mob[i];          }          sum[i] = sum[i - 1] + mob[i];      }  }     int cal(int l, int r)  {      if(l > r)          swap(l, r);      int ans = 0;      for(int i = 1, last = 0; i <= l; i = last + 1)      {          last = min(l / (l / i), r / (r / i));          ans += (l / i) * (r / i) * (sum[last] - sum[i - 1]);      }      return ans;  }     int main()  {      Mobius();      int n;      scanf("%d", &n);      while(n --)      {          scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);          int ans = 0;          ans += cal(b / k, d / k);          ans -= cal((a - 1) / k, d / k);          ans -= cal((c - 1) / k, b / k);          ans += cal((a - 1) / k, (c - 1) / k);          printf("%d\n", ans);         }  }  




阅读全文
0 0
原创粉丝点击