Description
Input
第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k
Output
共n行,每行一个整数表示满足要求的数对(x,y)的个数
Sample Input
2 5 1 5 1
1 5 1 5 2
Sample Output
3
HINT
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
题解
记 $f(x, y)$ 为满足 $gcd(i,j)=k$ 的数对 $(i,j)~~(i\in[1,x],j\in[1,y])$ 的个数。
由容斥原理,答案就是 $ans=f(b,d)-f((a-1),d)-f(b,(c-1))+f((a-1),(c-1))$ 。
我们现在考虑如何求 $f(x,y)$ 。
我们按照以往的套路,将 $k$ 提出,显然 $$f(a,b)=\sum_{i=1}^{\left\lfloor\frac{a}{k} \right\rfloor}\sum_{j=1}^{\left\lfloor\frac{b}{k} \right\rfloor}[gcd(i,j)=1]$$
由公式 $\sum_{d\mid n} \mu(d)=[n=1]$ ,我们得到
$$\Rightarrow \sum_{i=1}^{\left\lfloor\frac{a}{k} \right\rfloor}\sum_{j=1}^{\left\lfloor\frac{b}{k} \right\rfloor}\sum_{d\mid gcd(i,j)}\mu(d)$$
我们将 $\mu$ 提前
\begin{aligned} &\Rightarrow\sum_{d=1}^{min\left\{\left\lfloor\frac{a}{k} \right\rfloor,\left\lfloor\frac{b}{k} \right\rfloor\right\}}\mu(d)\sum_{i=1,d\mid i}^{\left\lfloor\frac{a}{k} \right\rfloor}\sum_{j=1,d\mid j}^{\left\lfloor\frac{b}{k}\right\rfloor}1\\&\Rightarrow\sum_{d=1}^{min\left\{\left\lfloor\frac{a}{k} \right\rfloor,\left\lfloor\frac{b}{k} \right\rfloor\right\}}\mu(d)\cdot\left\lfloor\frac{\left\lfloor\frac{a}{k}\right\rfloor}{d}\right\rfloor\cdot\left\lfloor\frac{\left\lfloor\frac{b}{k}\right\rfloor}{d}\right\rfloor\end{aligned}
得到这个式子还有第二个方Fa♂,这里也提一下。
令 $F(d)$ 为 $d\mid gcd(i,j)$ 的数对 $(i,j)$ 个数, $f(d)$ 为 $d=gcd(i,j)$ 的数对 $(i,j)$ 个数。
由题 $$F(k)=\sum_{d=1}^{min\left\{\left\lfloor\frac{a}{k}\right\rfloor,\left\lfloor\frac{b}{k} \right\rfloor\right\}}f(kd)$$
由莫比乌斯反演定理 $F(n)=\sum_{n\mid d} f(d)\Rightarrow f(n)=\sum_{n\mid d} \mu(\frac{d}{n})F(d)$
\begin{aligned}\Rightarrow f(k)&=\sum_{d=1}^{min\left\{\left\lfloor\frac{a}{k}\right\rfloor,\left\lfloor\frac{b}{k}\right\rfloor\right\}}\mu(d)F(kd)\\&=\sum_{d=1}^{min\left\{\left\lfloor\frac{a}{k} \right\rfloor,\left\lfloor\frac{b}{k}\right\rfloor\right\}}\mu(d)\cdot\left\lfloor\frac{a}{kd}\right\rfloor\cdot\left\lfloor\frac{b}{kd}\right\rfloor\end{aligned}
那么我们现在只需要 $O(n)$ 的枚举 $d$ 就可以了,但对于多组询问,这个复杂度还是吃不消的。
我们考虑在计算的时候 $\left\lfloor\frac{\left\lfloor\frac{n}{k}\right\rfloor}{d}\right\rfloor$ 是一个分段的,有较长的一段区间内的数是相等的。可以证明这段区间的长度是 $\sqrt{n}$ 的。
证明:
1.当 $1\leq d < \sqrt n$ 时, $d$ 就只有 $\sqrt n$ 个, $\left\lfloor{n \over d}\right\rfloor$ 最多有 $\sqrt n$ 个。
2.当 $\sqrt n \leq d \leq n$ 时,由于 $\left\lfloor{n \over d}\right\rfloor$ 小于 $\sqrt n$ ,所以 $\left\lfloor{n \over d}\right\rfloor$ 最多有 $\sqrt n$ 个。
证毕。
显然对于一段区间内 $\left\lfloor\frac{\left\lfloor\frac{a}{k}\right\rfloor}{d}\right\rfloor$ 和 $\left\lfloor\frac{\left\lfloor\frac{b}{k}\right\rfloor}{d}\right\rfloor$ 相同的数我们可以直接处理 $\mu$ 的前缀,直接求即可。而相同值的区间的右端点为 $\left\lfloor \frac{n}{\left\lfloor\frac{n}{d} \right\rfloor} \right\rfloor$ 。
证明:
对于 $n$ 来说,找到最大的 $j$ 满足 $$\left\lfloor\frac{n}{i}\right\rfloor \leq\left\lfloor\frac{n}{j}\right\rfloor$$
化简一下得到 $$j\leq \left\lfloor\frac{n}{\left\lfloor\frac{n}{i}\right\rfloor}\right\rfloor$$
那么在计算时在分别关于 $a, b$ 的表达式中取一个较小值即可。时间复杂度 $O(n\sqrt n)$ 。
1 //It is made by Awson on 2018.1.19 2 #include <set> 3 #include <map> 4 #include <cmath> 5 #include <ctime> 6 #include <queue> 7 #include <stack> 8 #include <cstdio> 9 #include <string> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 #define LL long long 16 #define Abs(a) ((a) < 0 ? (-(a)) : (a)) 17 #define Max(a, b) ((a) > (b) ? (a) : (b)) 18 #define Min(a, b) ((a) < (b) ? (a) : (b)) 19 #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b)) 20 #define writeln(x) (write(x), putchar(‘\n‘)) 21 using namespace std; 22 const int N = 50000; 23 const int INF = ~0u>>1; 24 void read(int &x) { 25 char ch; bool flag = 0; 26 for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == ‘-‘)) || 1); ch = getchar()); 27 for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar()); 28 x *= 1-2*flag; 29 } 30 void write(LL x) { 31 if (x > 9) write(x/10); 32 putchar(x%10+48); 33 } 34 35 LL mu[N+5]; int a, b, c, d, k; 36 void get_mu() { 37 int isprime[N+5], prime[N+5], tot = 0; 38 memset(isprime, 1, sizeof(isprime)); isprime[1] = 0, mu[1] = 1; 39 for (int i = 2; i <= N; i++) { 40 if (isprime[i]) mu[i] = -1, prime[++tot] = i; 41 for (int j = 1; j <= tot && i*prime[j] <= N; j++) 42 if (!(i%prime[j])) {isprime[i*prime[j]] = 0, mu[i*prime[j]] = 0; break; } 43 else isprime[i*prime[j]] = 0, mu[i*prime[j]] = -mu[i]; 44 mu[i] += mu[i-1]; 45 } 46 } 47 LL cal(int x, int y) { 48 if (x > y) Swap(x, y); LL ans = 0; 49 for (int i = 1, last; i <= x; i = last+1) { 50 last = Min(x/(x/i), y/(y/i)); 51 ans += (LL)(mu[last]-mu[i-1])*(x/i)*(y/i); 52 } 53 return ans; 54 } 55 void work() { 56 read(a), read(b), read(c), read(d), read(k); 57 writeln(cal(b/k, d/k)-cal(b/k, (c-1)/k)-cal((a-1)/k, d/k)+cal((a-1)/k, (c-1)/k)); 58 } 59 int main() { 60 int t; read(t); get_mu(); 61 while (t--) work(); 62 return 0; 63 }