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
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 }