[luogu]P2522 [HAOI2011]Problem b[莫比乌斯反演]

题目

T组询问,每组询问A,B,C,D,K共5个参数计算\sum_{A \leq x \leq B,C \leq y \leq D} [gcd(x,y)==k]

数据范围:所有value \leq 50000

题解

具体解释参考两两gcd问题求解各种思路

F[x],f[x]分别为gcd(i,j)(1 \leq i \leq N,1 \leq j \leq M)x​​​​​​倍数和等于x的个数,有F[n]=\sum_{n|d}f[d]=\lfloor \frac{N}{n} \rfloor\lfloor \frac{M}{n} \rfloor

由莫比乌斯反演知:f[n]=\sum_{n|d}\mu (\frac{d}{n})F[d]

问题即求f^{'}[K],由于上界下界的问题,利用容斥分别计算即可:

以上界进行表示ans=solve(B,D)-solve(A-1,D)-solve(B,C-1)+solve(A-1,B-1)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

using LL = long long;
const int MAXN = 5e4 + 5;
int T, A, B, C, D, K;
bool noprime[MAXN];
int prime[MAXN], cnt_p, mu[MAXN];
void Euler_sieve(int top);
int pre[MAXN];
LL solve(int, int);

int main(){
  ios::sync_with_stdio(false);
  Euler_sieve(5e4);
  cin >> T;
  while(T--){
    cin >> A >> B >> C >> D >> K;
    LL ans = 0;
    ans += solve(B / K, D / K);
    ans -= solve(B / K, (C - 1) / K) + solve((A - 1) / K, D / K);
    ans += solve((A - 1) / K, (C - 1) / K);
    cout << ans << endl;
  }
  return 0;
}

LL solve(int n, int m){
  int l, r, top = min(n, m); LL res = 0;
  for(l = 1; l <= top; l = r + 1){
    r = min(n / (n / l), m / (m / l));
    res += 1LL * (pre[r] - pre[l - 1]) * (n / l) * (m / l);
  }
  return res;
}

void Euler_sieve(int top){
  int i, j;
  mu[1] = 1;
  for(i = 2; i <= top; i++){
    if(!noprime[i]) prime[++cnt_p] = i, mu[i] = -1;
    for(j = 1; j <= cnt_p && prime[j] * i <= top; j++){
      noprime[prime[j] * i] = true;
      if(i % prime[j] == 0) break;
      mu[prime[j] * i] = -mu[i];
    }
  }

  for(i = 1; i <= top; i++) pre[i] = pre[i - 1] + mu[i];
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值