bzoj 2301 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


  题目大意 (如此简洁的题目就不需要我的烂文笔了)

  这是在迎接codeforces div 2一场(灰)之前恭迎的最后的一道水题(一个名为Doggu的数论神犇这么说的)。好了,废话不多说了。

  如果你还没有做过bzoj 1101,那你应该赶紧做一下咯。

  推理和它一毛一样,然后你发现它求的实际上等于一个二维前缀和,于是它便真地成了一道水题了(你基本上不用改动什么,copy过来,二维前缀和加加减减就水掉了)。

Code

  1 /**
  2  * bzoj
  3  * Problem#2301
  4  * Accepted
  5  * Time:14640ms
  6  * Memory:1576k
  7  */
  8 #include <iostream>
  9 #include <cstdio>
 10 #include <ctime>
 11 #include <cmath>
 12 #include <cctype>
 13 #include <cstring>
 14 #include <cstdlib>
 15 #include <fstream>
 16 #include <sstream>
 17 #include <algorithm>
 18 #include <map>
 19 #include <set>
 20 #include <stack>
 21 #include <queue>
 22 #include <vector>
 23 #include <list>
 24 #ifndef WIN32
 25 #define Auto "%lld"
 26 #else
 27 #define Auto "%I64d"
 28 #endif
 29 using namespace std;
 30 typedef bool boolean;
 31 const signed int inf = (signed)((1u << 31) - 1);
 32 const signed long long llf = (signed long long)((1ull << 61) - 1);
 33 const double eps = 1e-6;
 34 const int binary_limit = 128;
 35 #define smin(a, b) a = min(a, b)
 36 #define smax(a, b) a = max(a, b)
 37 #define max3(a, b, c) max(a, max(b, c))
 38 #define min3(a, b, c) min(a, min(b, c))
 39 template<typename T>
 40 inline boolean readInteger(T& u){
 41     char x;
 42     int aFlag = 1;
 43     while(!isdigit((x = getchar())) && x != '-' && x != -1);
 44     if(x == -1) {
 45         ungetc(x, stdin);    
 46         return false;
 47     }
 48     if(x == '-'){
 49         x = getchar();
 50         aFlag = -1;
 51     }
 52     for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0');
 53     ungetc(x, stdin);
 54     u *= aFlag;
 55     return true;
 56 }
 57 
 58 const int limit = 5e4;
 59 
 60 int n;
 61 int num = 0;
 62 int prime[10000];
 63 int miu[limit + 1];
 64 boolean vis[limit + 1];
 65 
 66 inline void Euler() {
 67     memset(vis, false, sizeof(vis));
 68     miu[0] = 0, miu[1] = 1;
 69     for(int i = 2; i <= limit; i++) {
 70         if(!vis[i])    miu[i] = -1, prime[num++] = i;
 71         for(int j = 0; j < num && prime[j] * 1LL * i <= limit; j++) {
 72             int c = prime[j] * i;
 73             vis[c] = true;
 74             if((i % prime[j]) == 0) {
 75                 miu[c] = 0;
 76                 break;
 77             } else {
 78                 miu[c] = -1 * miu[i];
 79             }
 80         }
 81         miu[i] += miu[i - 1];
 82     }
 83 }
 84 
 85 inline void init() {
 86     readInteger(n);
 87 }
 88 
 89 inline long long calc(int a, int b, int d) {
 90     long long ret = 0;
 91     a /= d, b /= d;
 92     if(a == 0 || b == 0)    return 0;
 93     if(a > b)    swap(a, b);
 94     ret = 0;
 95     for(int i = 1, j; i <= a; i = j + 1) {
 96         j = min(a / (a / i), b / (b / i));
 97         ret += (a / j) * 1LL * (b / j) * (miu[j] - miu[i - 1]);
 98     }
 99     return ret;
100 }
101 
102 inline void solve() {
103     int a, b, c, d, e;
104     while(n--) {
105         scanf("%d%d%d%d%d", &a, &b, &c, &d, &e);
106         printf(Auto"\n", calc(b, d, e) - calc(a - 1, d, e) - calc(c - 1, b, e) + calc(a - 1, c - 1, e));
107     }
108 }
109 
110 int main() {
111     Euler();
112     init();
113     solve();
114     return 0;
115 }

 

posted @ 2017-07-24 22:19 阿波罗2003 阅读(...) 评论(...) 编辑 收藏