[HAOI2011]Problem b

化成数学代数式就是这样:

$$\sum_{x=a}^b\sum_{y=c}^d[\gcd(x,y)=k]$$

根据差分的思想,可以将该式变成:

$$\sum_{x=1}^b\sum_{y=1}^d[\gcd(x,y)=k]-\sum_{x=1}^{a-1}\sum_{y=1}^d[\gcd(x,y)=k]-\sum_{x=1}^b\sum_{y=1}^{c-1}[\gcd(x,y)=k]+\sum_{x=1}^{a-1}\sum_{y=1}^{b-1}[\gcd(x,y)=k]$$

只要求出:

$$\sum_{i=1}^N\sum_{j=1}^M[\gcd(i,j)=k]$$

最后的答案就能求解。

我们来推导这个式子:

$$\begin{array}{ll} &\sum\limits_{i=1}^N\sum\limits_{j=1}^M[\gcd(i,j)=k]\\=&\sum\limits_{i=1}^{\lfloor\frac Nk\rfloor}\sum\limits_{j=1}^{\lfloor\frac Mk\rfloor}[\gcd(i,j)=1]\\ =&\sum\limits_{i=1}^{\lfloor\frac Nk\rfloor}\sum\limits_{j=1}^{\lfloor\frac Mk\rfloor}\epsilon(\gcd(i,j)) & \text{根据单位函数ϵ的定义}\\=&\sum\limits_{i=1}^{\lfloor\frac Nk\rfloor}\sum\limits_{j=1}^{\lfloor\frac Mk\rfloor}\sum\limits_{d|gcd(i,j)}\mu(d)&\text{注意这一步的变换是根据} \epsilon=\mu*1 \text{得来的}\\=&\sum\limits_{i=1}^{\lfloor\frac Nk\rfloor}\sum\limits_{j=1}^{\lfloor\frac Mk\rfloor}\sum\limits_{d|i,d|j}\mu(d)\\=&\sum\limits_{d=1}^{\min(N,M)}\mu(d)\sum\limits_{d|i,i\leq \lfloor\frac Nk\rfloor}\sum\limits_{d|j,j\leq \lfloor\frac Mk\rfloor}&\text{调换求和顺序} \\=&\sum\limits_{d=1}^{\min(N,M)}\mu(d) \lfloor \frac{\lfloor \frac Nk \rfloor}d \rfloor \lfloor \frac{\lfloor \frac Mk \rfloor}d \rfloor \end{array}$$

现在可以用$O(\min(N,M))$的复杂度解决,但还不够。我们要用一种科技:整除分块

有一个性质:一个数$N$整除任意数,商最多有$2\sqrt{N}$种不同的数;

证明:设除数$d$,当$d\leq \sqrt{N}$,最多有$\sqrt{N}$种除数;当$d\leq \sqrt{N}$,$0\leq\left\lfloor \dfrac Nd \right\rfloor\leq \sqrt{N}$最多只有$\sqrt{N}$种,综上最多有$2\sqrt{N}$种。

再一个性质:一个数$N$与另一个正整数$l$整除为$d$,在$d$不变的情况下,$l$的最大值$l'$为$\left\lfloor \dfrac N{\lfloor \frac Nl \rfloor} \right\rfloor$;

证明:回想下小学的东西:被除数一定,商越小,除数越大。因为是整除,所以商是整数,如果不是整除,商$d'$一定满足$d\leq d' <d+1$,所以除数最大时最小的商$d'=d=\left\lfloor\dfrac Nl\right\rfloor$。除数的最大值$l'$就是$\left\lfloor \dfrac N{\lfloor \frac Nl \rfloor} \right\rfloor$了(加下取整是因为$l'$是整数)。

根据上面两个性质,算法就应运而生了。

代码实现(这里用$r$代替了上面的$l'$):

for (int l = 1, r; l <= N; l = r+1) {
    r = N / (N / l);
    // do something
}

 复杂度为$O(\sqrt{N})$。

然后我们可以通过分块求出当商相等的$d$的区间再乘上$\mu$的前缀差分即可。

关于$\mu$的求解,因为是积性函数,可以用线性筛筛出,复杂度$O(\text{size})$,然后直接前缀处理,最后分块统计即可。

整体复杂度:$O(T\sqrt N)$,这里$T$是数据组数,$N$为$a,b,c,d$的范围。详见底下的代码。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 8 #define srep(i, a, b, c) for (re int i = a; i <= b; c)
 9 #define maxx(a, b) a = max(a, b);
10 #define minn(a, b) a = min(a, b);
11 #define LL long long
12 #define INF (1 << 30)
13 
14 inline int read() {
15     int w = 0, f = 1; char c = getchar();
16     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
17     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
18     return w * f;
19 }
20 
21 const int maxn = 5e4 + 5;
22 
23 int mu[maxn], vis[maxn], p[maxn], prime_tot;
24 
25 void get_mu() {
26     prime_tot = 0;
27     memset(vis, 0, sizeof(vis));
28     mu[1] = 1; int size = 50000;
29     rep(i, 2, size) {
30         if (!vis[i]) {
31             p[prime_tot++] = i;
32             mu[i] = -1;
33         }
34         rep(j, 0, prime_tot-1) {
35             if (i * p[j] > size) break;
36             vis[i * p[j]] = 1;
37             if (!(i % p[j])) {
38                 mu[i * p[j]] = 0;
39                 break;
40             }
41             mu[i * p[j]] = -mu[i];
42         }
43     }
44     rep(i, 2, size) mu[i] += mu[i-1];
45 }
46 
47 LL calc(int m, int n, int k) {
48     m /= k, n /= k;
49     int loop = min(m, n);
50     LL ans = 0;
51     for (int l = 1, r; l <= loop; l = r+1) {
52         r = min(n / (n / l), m / (m / l));
53         ans += 1ll * (mu[r]-mu[l-1]) * (1ll * (n/l)*(m/l));
54     }
55     return ans;
56 }
57 
58 int a, b, c, d, e, n;
59 
60 int main() {
61     n = read();
62     get_mu();
63     while (n--) {
64         a = read(), b = read(), c = read(), d = read(), e = read();
65         printf("%lld\n", calc(b, d, e) - calc(a-1, d, e) - calc(b, c-1, e) + calc(a-1, c-1, e));
66     }
67     return 0;
68 }

 

posted @ 2019-02-13 22:57  AC-Evil  阅读(218)  评论(0编辑  收藏  举报