洛谷P3455 [POI2007][BZOJ1101]ZAP-Queries(莫比乌斯反演 + 分块)

洛谷P3455 [POI2007][BZOJ1101]ZAP-Queries

题目

Description

Byteasar the Cryptographer works on breaking the code of BSA (Byteotian Security Agency). He has alreadyfound out that whilst deciphering a message he will have to answer multiple queries of the form"for givenintegers a a , b b and d d , find the number of integer pairs ( x , y ) (x,y) satisfying the following conditions:
1 x a , 1 y b , g c d ( x , y ) = d 1\le x\le a,1\le y\le b,gcd(x,y)=d , where g c d ( x , y ) gcd(x,y) is the greatest common divisor of x x and y y ".
Byteasar would like to automate his work, so he has asked for your help.
TaskWrite a programme which:
reads from the standard input a list of queries, which the Byteasar has to give answer to, calculates answers to the queries, writes the outcome to the standard output.


FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数 a a , b b d d ,有多少正整数对 x x , y y ,满足 x a x\le a y b y \le b ,并且 g c d ( x , y ) = d gcd(x,y)=d 。作为FGD的同学,FGD希望得到你的帮助。

Input

The first line of the standard input contains one integer n n ( 1 n 50   000 1\le n\le 50\ 000 ),denoting the number of queries.
The following n n lines contain three integers each: a a , b b and d d ( 1 d a , b 50   000 1\le d\le a,b\le 50\ 000 ), separated by single spaces.
Each triplet denotes a single query.

Output

Your programme should write n n lines to the standard output. The i i 'th line should contain a single integer: theanswer to the i i 'th query from the standard input.

Sample Input

2
4 5 2
6 4 3

Sample Output

3
2

HINT

对于第一组询问,满足条件的整数对有 ( 2 , 2 ) , ( 2 , 4 ) , ( 4 , 2 ) (2,2),(2,4),(4,2) 。对于第二组询问,满足条件的整数对有 ( 6 , 3 ) , ( 3 , 3 ) (6,3),(3,3)

题解

由题可知,需要我们求
x = 1 a y = 1 b [ g c d ( x , y ) = d ] \sum_{x=1}^{a}\sum_{y=1}^{b}[gcd(x,y)=d]
那我们可以令 a = a d ,   b = b d a'={a \over d},\ b'={b\over d}
此时,求解 x = 1 a y = 1 b [ g c d ( x , y ) = d ] \sum_{x=1}^{a}\sum_{y=1}^{b}[gcd(x,y)=d] 即是求解 x = 1 a y = 1 b [ g c d ( x , y ) = 1 ] \sum_{x=1}^{a'}\sum_{y=1}^{b'}[gcd(x,y)=1]


由莫比乌斯函数的性质可以知道 d n μ ( d ) = [ n = 1 ] \sum_{d|n}\mu(d)=[n=1]
我们可以尝试把式子里的 n n 换成 g c d ( x , y ) gcd(x,y)
d g c d ( x , y ) μ ( d ) = [ g c d ( x , y ) = 1 ] \sum_{d|gcd(x,y)}\mu(d)=[gcd(x,y)=1]
式子可变为:
x = 1 a y = 1 b d g c d ( x , y ) μ ( d ) \sum_{x=1}^{a'}\sum_{y=1}^{b'}\sum_{d|gcd(x,y)}\mu(d)

又知 d g c d ( x , y )     d x   a n d   d y d|gcd(x,y)\ \rightarrow\ d|x\ and\ d|y
将和式前移,可得
d = 1 m i n ( a , b ) μ ( d ) x = 1 a [ d x ] y = 1 b [ d y ] \sum_{d=1}^{min(a',b')}\mu(d)\sum_{x=1}^{a'}[d|x]\sum_{y=1}^{b'}[d|y]
再把形如 i = 1 n [ d i ] \sum_{i=1}^{n}[d|i] 化简为 n d \lfloor{n \over d}\rfloor
d = 1 m i n ( a , b ) μ ( d ) a d b d \sum_{d=1}^{min(a',b')}\mu(d)\lfloor{\frac{a'}{d}}\rfloor\lfloor{\frac{b'}{d}}\rfloor
此时如果暴力计算,则复杂度为 O ( n ) O(n) ,但是可以观察到 a d \lfloor{\frac{a'}{d}}\rfloor b d \lfloor{\frac{b'}{d}}\rfloor 是有大量重复的,于是可以用到前面整除分块的知识。利用整除分块和 μ ( d ) \mu(d) 的前缀和相乘,可将复杂度优化到 O ( n ) O(\sqrt{n})

代码

#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 && prime[j] * i < 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 t, a, b, d;
  scanf("%d", &t);
  while (t--) {
    scanf("%d %d %d", &a, &b, &d);
    printf("%d\n", solve(a/d, b/d));
  }


  return 0;
}
发布了79 篇原创文章 · 获赞 56 · 访问量 50万+

猜你喜欢

转载自blog.csdn.net/qq_40861916/article/details/90650551