[HAOI2011]Problem b
题意
组询问,给定 , 求 并且 = 的数对数量。
()
解题思路
- 定义 表示 并且 满足 的数对数量。
容斥易得,本题的答案即是:
那么现在我们的目标是在 的时间内快速求出
考虑对于原式进行化简,原式即:
首先是把原式里面的 提出来:
下一步则是 转化为 :
又因为 : 等价于 &&
然后我们可以知道, 内的所有数中 的倍数一共有 个。所以式子进一步化简:
现在就可以整一个整除分块乱搞哩!1
#include <bits/stdc++.h> using namespace std; #define int long long inline int read() { int x = 0, flag = 1; char ch = getchar(); for( ; ch > '9' || ch < '0' ; ch = getchar()) if(ch == '-') flag = -1; for( ; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + ch - '0'; return x * flag; } const int MAXN = 1e5 + 500; int Prime[MAXN], mu[MAXN],tot = 0; bool book[MAXN]; int T,a,b,c,d,k; void GetPrime() { mu[1] = 1; for(int i = 2 ; i <= 6e4 ; i ++) { if(!book[i]) Prime[++ tot] = i, mu[i] = -1; for(int j = 1 ; j <= tot ; j ++) { if(Prime[j] * i > 6e4) break; book[Prime[j] * i] = 1; if(i % Prime[j] == 0) break; mu[i * Prime[j]] = -mu[i]; } } for(int i = 1 ; i <= 6e4 ; i ++) mu[i] = mu[i - 1] + mu[i]; return ; } int calc(int a, int b) { int Ans = 0; int mx=a / k, my = b / k; for(int l = 1 ,r ;l <= min (mx, my) ; l = r + 1) { r = min(mx / (mx / l), my / (my / l)); Ans += (mx / l) * (my / l) * (mu[r] - mu[l - 1]); } return Ans; } signed main() { GetPrime(); T = read(); while(T --) { a = read(), b = read(), c = read(), d = read(); k = read(); printf("%lld\n", calc(b, d) - calc(b, c - 1) - calc(a - 1, d) + calc(a - 1, c - 1)); } return 0; }