[Problem b HYSBZ - 2301][GCD HDU - 1695] 莫比烏斯反演 + 容斥 + 分塊

Problem b HYSBZ - 2301

對於給出的 nn 個詢問,每次求有多少個數對 (x,y)(x,y) ,滿足 axba ≤ x ≤ bcydc ≤ y ≤ d ,且 gcd(x,y)=kgcd(x,y) = kgcd(x,y)gcd(x,y) 函數爲 xxyy 的最大公約數。

Input

第一行一個整數 nn,接下來 nn 行每行五個整數,分別表示 abcdka、b、c、d、k

Output

nn 行,每行一個整數表示滿足要求的數對 (x,y)(x,y) 的個數

Sample Input

2
2 5 1 5 1
1 5 1 5 2

Sample Output

14
3

Hint

100%100\% 的數據滿足:1n500001ab500001cd500001k500001≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

題解

題目求解
x=aby=cd[gcd(x,y)=k]\sum_{x = a}^{b}\sum_{y = c}^{d}[gcd(x, y) = k]

f=[gcd(x,y)=k]f=[gcd(x,y)=k]
根據容斥的原理,我們可以知道
x=aby=cdf=x=1by=1dfx=1a1y=1dfx=1by=1c1f+x=1a1y=1c1f\sum_{x = a}^{b}\sum_{y = c}^{d}f=\sum_{x = 1}^{b}\sum_{y = 1}^{d}f-\sum_{x = 1}^{a-1}\sum_{y = 1}^{d}f-\sum_{x = 1}^{b}\sum_{y = 1}^{c-1}f + \sum_{x = 1}^{a-1}\sum_{y = 1}^{c-1}f
所以重點在於 x=1ny=1mf\sum_{x = 1}^{n}\sum_{y = 1}^{m}f 的求法。
和以前一樣,令 n=nk,m=mkn'=\lfloor{n\over k}\rfloor,m'=\lfloor{m\over k}\rfloor
x=1ny=1m[gcd(x,y)=k]=x=1ny=1m[gcd(x,y)=1]=x=1ny=1mdgcd(x,y)μ(d)=d=1min(n,m)μ(d)ndmd\begin{aligned} \sum_{x = 1}^{n}\sum_{y = 1}^{m}[gcd(x,y)=k] & =\sum_{x = 1}^{n'}\sum_{y = 1}^{m'}[gcd(x, y)=1]\\ &=\sum_{x = 1}^{n'}\sum_{y = 1}^{m'}\sum_{d|gcd(x,y)}\mu(d)\\ &=\sum_{d=1}^{min(n',m')}\mu(d)*\lfloor{n'\over d}\rfloor * \lfloor{m'\over d}\rfloor\\ \end{aligned}
因此也可以分塊計算。

代碼

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 10;
int mu[maxn], prime[maxn], cnt = 0;
bool vis[maxn];

void init() {
  mu[1] = 1;
  for (int i = 2; i < maxn; i++) {
    if (vis[i] == false) {
      prime[cnt++] = i;
      mu[i] = -1;
    }
    for (int j = 0; j < cnt && i * prime[j] < maxn; j++) {
      vis[i * prime[j]] = true;
      if (i % prime[j] == 0) {
        mu[i * prime[j]] = 0;
        break;
      } else {
        mu[i * prime[j]] = -mu[i];
      }
    }
  }
  for (int i = 2; i < maxn; i++) {
    mu[i] += mu[i - 1];
  }
}

int solve(int a, int b) {
  int ans = 0;
  if (a > b) swap(a, b);
  for (int l = 1, r; l <= a; l = r + 1) {
    r = min(a/(a/l), b/(b/l));
    ans += (mu[r] - mu[l - 1]) * (a/l) * (b/l);
  }
  return ans;
}

int main()
{
  init();
  int n, a, b, c, d, k;
  scanf("%d", &n);
  while (n--) {
    scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
    printf("%d\n", solve(b/k, d/k) - solve(b/k, (c - 1)/k) - solve((a - 1)/k, d/k) + solve((a - 1)/k, (c - 1)/k));
  }

  return 0;
}

GCD HDU - 1695

Problem Description

Given 55 integers: a,b,c,d,k,a, b, c, d, k, you’re to find xx in a...ba...b, yy in c...dc...d that gcd(x,y)=kgcd(x, y) = k. gcd(x,y)gcd(x, y) means the greatest common divisor of xx and yy. Since the number of choices may be very large, you’re only required to output the total number of different number pairs.
Please notice that, (x=5,y=7x=5, y=7) and (x=7,y=5x=7, y=5) are considered to be the same.


You can assume that a=c=1a = c = 1 in all test cases.

Input

The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,0003,000 cases.
Each case contains five integers: a,b,c,d,k,0&lt;ab100,000,0&lt;cd100,000,0k100,000a, b, c, d, k, 0 &lt; a \le b \le 100,000, 0 &lt; c \le d \le 100,000, 0 \le k \le 100,000, as described above.

Output

For each test case, print the number of choices. Use the format in the example.

Sample Input

2
1 3 1 5 1
1 11014 1 14409 9

Sample Output

Case 1: 9
Case 2: 736427

Hint

For the first sample input, all the 99 pairs of numbers are (1,1),(1,2),(1,3),(1,4),(1,5),(2,3),(2,5),(3,4),(3,5)(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).

題解

起始這題和上題差不多,一樣的容斥。但是不同的是在這題看來,(2,3)(2,3)(3,2)(3,2) 被看作是同樣的一對,只計數一次。
題目已經說明保證 a=c=1a = c = 1
所以我們只需要容斥進行這樣子的處理:
f=[gcd(x,y)=k]f=[gcd(x,y) =k]
num(f)=x=1by=1dfx=1min(b,d)y=1min(b,d)f2num(f)=\sum_{x=1}^{b}\sum_{y=1}^{d}f-{\sum_{x=1}^{min(b,d)}\sum_{y=1}^{min(b,d)}f\over2}
想想爲什麼?


因爲只有滿足 x,y[1,min(b,d)]x,y \in [1, min(b,d)] 纔會有重複對的情況吧?

接下來對式子的處理也很容易。

代碼

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;
int mu[maxn],prime[maxn], cnt = 0;
bool vis[maxn];

void init() {
  mu[1] = 1;
  for (int i = 2; i < maxn; i++) {
    if (vis[i] == false) {
      prime[cnt++] = i;
      mu[i] = -1;
    }
    for (int j = 0; j < cnt && prime[j] * i < maxn; j++) {
      vis[prime[j] * i] = true;
      if (i % prime[j] == 0) {
        mu[i * prime[j]] = 0;
        break;
      } else {
        mu[i * prime[j]] = -mu[i];
      }
    }
  }
  for (int i = 2; i < maxn; i++) {
    mu[i] += mu[i - 1];
  }
}

LL solve(int a, int b) {
  LL ans = 0;
  for (int l = 1, r; l <= a; l = r + 1) {
    r = min(a/(a/l), b/(b/l));
    ans += (LL)(mu[r] - mu[l - 1]) * (a/l) * (b/l);
  }
  return ans;
}

int main()
{
  init();
  int a, b, c, d, k, n;
  scanf("%d", &n);
  for (int ca = 0; ca < n; ca++) {
    scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
    if (k == 0) {
      printf("Case %d: 0\n", ca + 1);
      continue;
    }
    if (b > d) swap(b, d);
    printf("Case %d: %lld\n", ca + 1, solve(b/k, d/k) - solve(b/k, b/k)/2);
  }

  return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章