Bzoj P2301 [HAOI2011]Problem b___莫比乌斯反演+容斥

题目大意:

对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。

1n500001ab500001≤n≤50000,1≤a≤b≤50000
1cd500001k500001≤c≤d≤50000,1≤k≤50000

分析:

dx,yd_{x,y}表示i=1xj=1y[gcd(i,j)=k]\sum_{i=1}^{x}\sum_{j=1}^{y}[gcd(i,j)=k]
那答案容斥一下可以知道就是db,dda1,ddb,c1+da1,c1d_{b,d}-d_{a-1,d}-d_{b,c-1}+d_{a-1,c-1}
那么我们考虑求dx,yd_{x,y}
dx,yd_{x,y}
=i=1xj=1ygcd(i,j)=k\sum_{i=1}^{x}\sum_{j=1}^{y}gcd(i,j)=k
=i=1xkj=1yk[gcd(i,j)=1]=\sum_{i=1}^{\left \lfloor \frac{x}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{y}{k} \right \rfloor}[gcd(i,j)=1]
我们知道莫比乌斯函数有一个性质,
dnμ(d)=[n=1]\sum_{d|n}μ(d)=[n=1]
那么当gcd(i,j)=1gcd(i,j)=1时,
显然dgcd(i,j)μ(d)=1\sum_{d|gcd(i,j)}μ(d)=1
那么
i=1xkj=1yk[gcd(i,j)=1]\sum_{i=1}^{\left \lfloor \frac{x}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{y}{k} \right \rfloor}[gcd(i,j)=1]
就可以写成
=i=1xkj=1ykdgcd(i,j)μ(d)=\sum_{i=1}^{\left \lfloor \frac{x}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{y}{k} \right \rfloor} \sum_{d|gcd(i,j)}μ(d)
然后这个东西可以转换一下,安利一个博客,
https://www.cnblogs.com/NaVi-Awson/p/8318709.html
在这里插入图片描述
然后我们对于所有的nkd\left \lfloor \frac{n}{kd} \right \rfloor,可以发现取值最多只有n\sqrt{n}种,并且相同的都是连续的一段,那么我们就可以愉快的预处理出mobiusmobius函数的前缀和,然后分块处理nkd\left \lfloor \frac{n}{kd} \right \rfloor,就可以求出 =i=1xkj=1ykdgcd(i,j)μ(d)=\sum_{i=1}^{\left \lfloor \frac{x}{k} \right \rfloor}\sum_{j=1}^{\left \lfloor \frac{y}{k} \right \rfloor} \sum_{d|gcd(i,j)}μ(d),就可以让每次查询的复杂度都达到根号级别。

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#define N 50005
 
using namespace std;
 
typedef long long ll;
 
int prime[N], check[N], sum[N], mu[N], T, a, b, c, d, k, cnt;
 
void Get_mobius()
{
    mu[1] = 1;
    for (int i = 2; i <= 50000; i++)
    {
         if (!check[i])
         {
             prime[++cnt] = i;
             mu[i] = -1;
         }
         for (int j = 1; j <= cnt; j++)
         {
              if (prime[j] * i > 50000) break;
              check[prime[j] * i] = 1;
              if (i % prime[j] == 0) { mu[prime[j] * i] = 0; break; }
                                else mu[prime[j] * i] = - mu[i];
         }
    }
    for (int i = 1; i <= 50000; i++) sum[i] = sum[i - 1] + mu[i];
}
 
ll Cal(int x, int y) 
{
    ll num = 0;
    if (x > y) swap(x, y);
    for (int i = 1, last; i <= x; i = last + 1)
    {
         last = min(x / (x / i), y / (y / i));
         num += (ll)(sum[last] - sum[i - 1]) * (x  / i) * (y / i);
    }
    return num;
}
 
int main()
{
    Get_mobius();
    scanf("%d", &T);
    while (T--)
    {
           scanf("%d %d %d %d %d", &a, &b, &c, &d, &k);
           ll ans = Cal(b / k, d / k) - Cal((a - 1) / k, d / k) - Cal(b / k, (c - 1) / k) + Cal((a - 1) / k, (c - 1) / k);
           printf("%lld\n", ans);
    }
    return 0;
}

发布了694 篇原创文章 · 获赞 364 · 访问量 15万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览