这题首先要将等式两边除以k,这样在求两边的互质数的个数就是最后的结果了。我们采用的策略就是用小区间的每一个数去匹配大区间的数。但是如果每次都去分解一个数的质因子的话,那么会TLE,因此先预处理出1-100000每个数的质因子再进行计算。
代码如下:
#include <cstring> #include <cstdlib> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; int a, b, c, d, k, rec[300000], idx; int start[100005], end[100005], S, E; long long int ret; void cut(int x) { int LIM = (int)sqrt(double(x)); if (x % 2 == 0) { rec[++idx] = 2; while (x % 2 == 0) { x /= 2; } } for (int i = 3; i <= LIM; i += 2) { if (x % i == 0) { rec[++idx] = i; while (x % i == 0) { x /= i; } } } if (x != 1) { rec[++idx] = x; } } void pre() { idx = 0; for (int i = 1; i <= 100000; ++i) { start[i] = idx; cut(i); end[i] = idx; } } void dfs(int p, int num, int sign, int &sum, int l, int r) { if (p == E) { if (num > 1) { sum += sign * (r / num - (l-1) / num); } return; } dfs(p+1, num, sign, sum, l, r); dfs(p+1, num*rec[p+1], -sign, sum, l, r); } int main() { int T, ca = 0, sum, l, r; pre(); scanf("%d", &T); while (T--) { ret = 0; scanf("%d %d %d %d %d", &a, &b, &c, &d, &k); printf( "Case %d: ", ++ca); if (!k) { puts("0"); continue; } b /= k, d /= k; if (b > d) { int t = b; b = d; d = t; } for (int i = 1; i <= b; ++i) { S = start[i], E = end[i]; sum = 0; l = i, r = d; dfs(S, 1, -1, sum, l, r); ret += (r-l+1) - sum; } printf("%I64d\n", ret); } return 0; }