[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;
}

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