1. 程式人生 > >hdu1695(莫比烏斯反演)

hdu1695(莫比烏斯反演)

ios targe .net ++ 其中 參考 http bool rim

題目鏈接: http://acm.hdu.edu.cn/showproblem.php?pid=1695

題意: 對於 a, b, c, d, k . 有 x 屬於 [a, b], y 屬於 [c, d], 求 gcd(x, y) = k 的 x, y 的對數 . 其中 a = b = 1 .

註意: (x, y), (y, x) 算一種情況 .

思路: 莫比烏斯反演

可以參考一下: http://blog.csdn.net/lixuepeng_001/article/details/50577932

公式: F(n) = sigma f(d) , 其中 (n | d) ==> f(n) = sigma u(d / n) * F(d) , 其中 (n | d) .

其中 u 為莫比烏斯函數, 定義為:

  若 d = 1, 則 u(d) = 1;

  若 d = p1p2...pk, 則 u(d) = (-1)^k , 其中 pi 為互異質數;

  其他 u(d) = 0;

對於 gcd(x, y) = k, 顯然有 gcd(x / k, y / k) = 1 . 那麽原題等價於求 gcd(x, y) = 1, 其中 x 屬於 (1, b / k), y 屬於 (1, d / k) .

然後定義 f(n) 表示滿足條件的 gcd(x,y) = n 的 (x, y) 對數,

再定義 F(n) 表示滿足 n | gcd(x,y) 的 (x, y) 對數, 即 gcd(x, y) % n = 0 的x, y對數 .

那麽我們要求的就是 f(1) .

通過前面推理不難發現 F(x) = n / x * m / x, 其中 n = b / k, m = d / k;

那麽 f(1) = sigma u(d / 1) * F(d), 其中 1 | d 且 d <= min(n, m);

即 f(1) = sigma u(d) * (n / d) * (m / d);

關於去重: f‘(1) = sigma u(d) * (n / d) * (n / d), 其中 n 為 m, n中的最小值, 則 sol = f(1) - f‘(1) / 2;

代碼:

技術分享
 1 #include <iostream>
 2 #include <stdio.h>
 3
#include <string.h> 4 #define ll long long 5 using namespace std; 6 7 const int MAXN = 1e6 + 10; 8 9 bool check[MAXN]; 10 int mu[MAXN], prime[MAXN]; 11 12 void Moblus(void){ 13 memset(check, false, sizeof(check)); 14 int tot = 0; 15 mu[1] = 1; 16 for(int i = 2; i < MAXN; i++){ 17 if(!check[i]){ 18 prime[tot++] = i; 19 mu[i] = -1; 20 } 21 for(int j = 0; j < tot && i * prime[j] < MAXN; j++){ 22 check[i * prime[j]] = true; 23 if(i % prime[j] == 0){ 24 mu[i * prime[j]] = 0; 25 break; 26 }else mu[i * prime[j]] = -mu[i]; 27 } 28 } 29 } 30 31 int main(void){ 32 int t, a, b, c, d, k; 33 Moblus(); 34 scanf("%d", &t); 35 for(int i = 1; i <= t; i++){ 36 scanf("%d%d%d%d%d", &a, &b, &c, &d, &k); 37 if(k == 0){ 38 printf("Case %d: 0\n", i); 39 continue; 40 } 41 if(b > d) swap(b, d); 42 b /= k; 43 d /= k; 44 ll ans1 = 0, ans2 = 0; 45 for(int j = 1; j <= b; j++){ 46 ans1 += (ll)mu[j] * (b / j) * (d / j); 47 } 48 for(int j = 1; j <= b; j++){ 49 ans2 += (ll)mu[j] * (b / j) * (b / j); 50 } 51 printf("Case %d: %lld\n",i, ans1 - (ans2 >> 1)); 52 } 53 return 0; 54 }
View Code

hdu1695(莫比烏斯反演)