1. 程式人生 > >51nod1222 最小公倍數計數 莫比烏斯反演 數學

51nod1222 最小公倍數計數 莫比烏斯反演 數學

求$\sum_{i = 1}^{n} \sum_{j = 1}^{i} [lcm(i, j) \le n]$
因為這樣不好求,我們改成求$\sum_{i = 1}^{n} \sum_{j = 1}^{n} [lcm(i, j) \le n]$.
這樣求出來的值把除了(i, i)這樣的點對以外所有點對都重複統計了一次。因此$ans = \frac{rnt + n}{2}$(先加上沒有重複統計的點對個數,使得所有點對都重複統計了一次,然後再除2就是不重複統計的點對個數)
接下來就是化式子了...
$$\sum_{i = 1}^{n} \sum_{j = 1}^{n} [lcm(i, j) \le n]$$
$$\sum_{i = 1}^{n} \sum_{j = 1}^{n} [\frac{ij}{(i, j)} \le n]$$
列舉$(i, j) = d$
$$\sum_{d = 1}^{n} \sum_{i = 1}^{n} \sum_{j = 1}^{n} [\frac{ij}{(i, j)} \le n] [(i, j) == d]$$
列舉$i = \frac{i}{d}$
$$\sum_{d = 1}^{n} \sum_{i = 1}^{\lfloor{ \frac{n}{d} }\rfloor} \sum_{j = 1}^{\lfloor{ \frac{n}{d} }\rfloor} [ijd \le n][(i, j) == 1]$$
上反演
$$\sum_{d = 1}^{n} \sum_{i = 1}^{\lfloor{ \frac{n}{d} }\rfloor} \sum_{j = 1}^{\lfloor{ \frac{n}{d} }\rfloor}[ijd \le n] \sum_{k | (i, j)} \mu(k)$$
$$\sum_{d = 1}^{n} \sum_{i = 1}^{\lfloor{ \frac{n}{d} }\rfloor} \sum_{j = 1}^{\lfloor{ \frac{n}{d} }\rfloor} \sum_{k | (i, j)} \mu(k)[ijd \le n]$$
把$k$提到前面來,然後列舉$k$的倍數
$$\sum_{d = 1}^{n} \sum_{k = 1}^{\lfloor{ \frac{n}{d} }\rfloor} \mu(k) \sum_{i = 1 }^{\lfloor{ \frac{n}{dk} }\rfloor} \sum_{j = 1}^{\lfloor{ \frac{n}{dk} }\rfloor}[i j k^2 d \le n]$$
可以發現,原式中對$d,k$的限制實際上是$dk \le n$,因此我們再次將$k$向前提,那麼此時$k$已經是第一個列舉的了,因此我們對中括號內的式子進行移項得到:
$$\sum_{k = 1}^{n} \mu(k) \sum_{d = 1}^{\lfloor{ \frac{n}{k} }\rfloor} \sum_{i = 1}^{\lfloor{ \frac{n}{dk} }\rfloor} \sum_{j = 1}^{\lfloor{ \frac{n}{dk} }\rfloor}[ijd \le \frac{n}{k^2}]$$
那麼為了保證$[ijd \le \frac{n}{k^2}]$,對現在列舉的變數有如下限制:
$k \le \sqrt{n}, d \le \lfloor{ \frac{n}{k^2} }\rfloor, x \le \lfloor{ \frac{n}{k^2d} }\rfloor, y \le \lfloor{ \frac{n}{k^2dx} }\rfloor$
因此原式變為:
$$\sum_{k = 1}^{\sqrt{n}} \mu(k) \sum_{d = 1}^{\lfloor{ \frac{n}{k^2} }\rfloor} \sum_{i = 1}^{\lfloor{ \frac{n}{k^2d} }\rfloor} \sum_{j = 1}^{\lfloor{ \frac{n}{k^2dx} }\rfloor} 1$$
設$H(n) = \sum_{a = 1}^{n} \sum_{b = 1}^{\lfloor{ \frac{n}{a} }\rfloor} \sum_{c = 1}^{\lfloor{ \frac{n}{ab} }\rfloor} 1$,則原式為:
$$\sum_{k = 1}^{\sqrt{n}} \mu(k) H(\lfloor{ \frac{n}{k^2} }\rfloor)$$
因此我們的目的就是快速求出$H(n)$。
$H(n)$可以看做是求滿足如下關係的三元組的個數$abc \le n$.
因此我們不妨假設$a < b < c$,那麼有$a \le n ^ {\frac{1}{3}}, b \le \sqrt{\lfloor{ \frac{n}{a} }\rfloor}$(因為除去$a$後剩餘數為$\lfloor{ \frac{n}{a} }\rfloor$,而$b$最大也要滿足$b \le c$,因此$b$最大也就是開根)
那麼此時$c$的範圍就為$[b + 1, \lfloor \frac{n}{ab} \rfloor]$,因此$c$的個數可以$O(1)$算出
因為我們假定了$a < b < c$,而原式中沒有這樣的限制,所以這樣會少算,比如$123$會被計算一次,但實際上應該被計算$123, 132, 213, 231, 321, 312$共$6$次。其他情況也是類似的。
因此我們列舉$a, b, c$,分別求3個均不相同,前2個相同,後2個相同,3個都相同的方案數,
然後對於這些方案數,分別乘上對應係數$6, 3, 3, 1$.最後加起來就等於$H(n)$.

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define AC 401000
 4 #define LL long long
 5 #define R register int
 6 #define RL register LL 
 7 
 8 LL l, r, tot, maxn;
 9 LL pri[AC], mu[AC];
10 bool z[AC];
11 
12 void pre()
13 {
14     scanf("%lld%lld", &l, &r), maxn = sqrt(r);
15 mu[1] = 1; 16 for(R i = 2; i <= maxn; i ++) 17 { 18 if(!z[i]) pri[++ tot] = i, mu[i] = -1; 19 for(R j = 1; j <= tot; j ++) 20 { 21 int now = pri[j]; 22 if(i * now > maxn) break; 23 z[i * now] = true; 24 if
(!(i % now)) break; 25 mu[i * now] = - mu[i]; 26 } 27 } 28 } 29 30 LL get(LL n) 31 { 32 LL A = 0, B = 0, C = 0, D = 0; 33 for(RL i = 1; i * i * i <= n; i ++)//列舉3個不相同的 34 { 35 LL m2 = sqrt(n / i), to = n / i;//因為k要從j + 1 列舉到 n / i / j,所以相減就是個數 36 for(RL j = i + 1; j <= m2; j ++) A += (LL)(to / j - j);//除法如此之慢。。。。 37 } 38 for(RL i = 1; i * i * i <= n; i ++) B += (LL)(n / i / i - i);//加上只有前2個相同的 39 for(RL i = 1; i * i * i <= n; i ++) C += ((LL)sqrt(n / i) - i);//列舉後2個相同的,因為後2個相同,所以只需要知道j的個數即可 40 for(RL i = 1; i * i * i <= n; i ++) ++ D;//因為詭異精度誤差,,,,就算是加減,也要先轉成LL.... 41 // D += m1;//因為前面是double型別,所以一遇到乘法,就可能造成進位。。。 42 return A * 6 + B * 3 + C * 3 + D; 43 } 44 45 LL cal(LL n) 46 { 47 int block = sqrt(n); LL rnt = 0; 48 for(R i = 1; i <= block; i ++) rnt += mu[i] * get(n / i / i); 49 return (rnt + n) / 2; 50 } 51 52 int main() 53 { 54 freopen("in.in", "r", stdin); 55 pre(); 56 printf("%lld\n", cal(r) - cal(l - 1)); 57 fclose(stdin); 58 return 0; 59 }
View Code