Java教程

2702. problem b

本文主要是介绍2702. problem b,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

题目链接

2702. problem b
同215. 破译密码

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

输入格式

第一行一个整数 \(n\)。

接下来 \(n\) 行每行五个整数,分别表示 \(a、b、c、d、k\)。

输出格式

共 \(n\) 行,每行一个整数表示满足要求的数对 \((x,y)\) 的个数。

数据范围

\(1 \le n \le 50000\),
\(1 \le a \le b \le 50000\),
\(1 \le c \le d \le 50000\),
\(1 \le k \le 50000\)

输入样例:

2
2 5 1 5 1
1 5 1 5 2

输出样例:

14
3

解题思路

莫比乌斯反演

本题单用容斥原理和莫比乌斯函数也可做:215. 破译密码

这里介绍莫比乌斯反演做法

先给出莫比乌斯函数的一个性质:\(\sum_{d \mid n} \mu(d)= \begin{cases}1 & n=1 \\ 0 & n \neq 1\end{cases}\) 。简略证明:\(n=1\) 时显然。当 \(n>1\) 时,对 \(n\) 分解质因数:\(n=\prod_{i=1}^{k} p_{i}^{c_{i}}\),当存在 \(c_i>1\) 时该项表示的约数的 \(d\) 的 \(\mu(d)=0\),这种情况的约数不考虑,即只用考虑 \(\prod_{i=1}^{k} p_{i}\) 的约数,即在这 \(k\) 个数中选出 \(1\) 个数组成约数,\(2\) 组成约数,\(3\) 个数组成约数,\(\dots\),组成 \(k\) 个数组成约数,由莫比乌斯函数,奇数种质数为 \(-1\),偶数种质数为 \(1\),则 \(\sum_{d \mid n} \mu(d)=\sum_{i=0}^{k} C_{k}^{i} \cdot(-1)^{i}=(1+(-1))^{k}=0\)
接着,有莫比乌斯反演的两条重要定理:

  1. 如果有 \(F(n)=\sum_{d \mid n} f(d)\) ,那么有 \(f(n)=\sum_{d \mid n} \mu(d) F\left(\frac{n}{d}\right)\)
    证明:将 \(F(n)=\sum_{d \mid n} f(d)\) 代入,得 \(\sum_{d \mid n} \mu(d) \sum_{i\mid \frac{n}{d}}f[i]\),观察 \(i\) 和 \(d\) 配对的情况,当 \(d=1\) 时 \(i\) 取遍 \(n\) 的约数,而对于某个固定的 \(i\),要求找出与 \(i\) 配对的 \(d\),这样的 \(d\) 需满足:\(d\mid n,i\mid \frac{n}{d}\),即 \(d\mid \frac{n}{i}\),此时可以交换 \(i,d\) 顺序,即:\(\sum_{i \mid n} f(i) \sum_{d\mid \frac{n}{i}}\mu(d)\),由莫比乌斯函数约数和性质,当且仅当 \(i=n\) 时后面的和不为 \(0\),即\(\sum_{i \mid n} f(i) \sum_{d\mid \frac{n}{i}}\mu(d)=f(n)\)

  2. 如果有 \(F(n)=\sum_{n \mid d} f(d)\) ,那么有 \(f(n)=\sum_{n \mid d} \mu\left(\frac{d}{n}\right) F(d)\)
    同理。这条定理常用。

本题按前缀和可转化为求解:\(\sum_{i=1}^{a} \sum_{j=1}^{b}[(i, j)=n]\),其中 \((i,j)\) 表示 \(i\) 和 \(j\) 的最大公约数

由莫比乌斯反演的性质,求解 \(F(n)\) 容易,求解 \(f(n)\) 困难,本题中 \(f(n)=\sum_{i=1}^{a} \sum_{j=1}^{b}[(i, j)=n]\),而由莫比乌斯反演第二条定理,可设定 \(F(n)=\sum_{i=1}^{a} \sum_{j=1}^{b}[n\mid (i, j)]\),其含义表示的是 \(x\in [1,a],y\in [1,b]\) 中 \(gcd(x,y)\) 是 \(n\) 的倍数的点数,\([1,a]\) 中有 \(a/n\) 个值是 \(n\) 的倍数,\([1,b]\) 中有 \(b/n\) 个值是 \(n\) 的倍数,由乘法原理,共有 \((a/n)\times (b/n)\) 个点满足要求,即 \(F(n)=(a/n)\times (b/n)\),则 $f(n)=\sum_{n \mid d} \mu\left(\frac{d}{n}\right)(a/d)\times (b/d) $,令 \(d'=\frac{d}{n}\),则 $f(n)=\sum_{d'} \mu(d')(a/d'n)\times (b/d'n) $,而倍数 \(d'\) 也不能无限大,$(d')(a/d'n)\times (b/d'n) $ 导致 \(d'\) 最大为 \(n=min(a/n,b/n)\),令 \(a=a/n,b=b/n\),即 $f(n)=\sum_{i=1}^n\mu(i)(a/i)\times (b/i) $,此时转化为单靠容斥原理得到的结论

  • 时间复杂度:\((n\sqrt{n})\)

代码

// Problem: problem b
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2704/
// Memory Limit: 64 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=5e4+5;
int q,a,b,c,d,k,m,prime[N],v[N],u[N],s[N];
void primes(int n)
{
    u[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(v[i]==0)
        {
            u[i]=-1;
            v[i]=prime[++m]=i;
        }
        for(int j=1;prime[j]*i<=n&&j<=m;j++)
        {
            if(v[i]<prime[j])break;
            if(i%prime[j]==0)
                u[i*prime[j]]=0;
            else
                u[i*prime[j]]=-u[i];
            v[i*prime[j]]=prime[j];

        }
    }
    for(int i=1;i<=n;i++)s[i]=s[i-1]+u[i];
}
int g(int a,int b)
{
	return a/(a/b);
}
LL f(int a,int b,int d)
{
	LL res=0;
	a/=d,b/=d;
	int n=min(a,b);
	for(int l=1,r;l<=n;l=r+1)
	{
		r=min({n,g(a,l),g(b,l)});
		res+=1ll*(s[r]-s[l-1])*(a/l)*(b/l);
	}
	return res;
}
int main()
{
    primes(N-1);
    cin>>q;
    while(q--)
    {
    	cin>>a>>b>>c>>d>>k;
    	cout<<f(b,d,k)-f(b,c-1,k)-f(a-1,d,k)+f(a-1,c-1,k)<<'\n';
    }
    return 0;
}
这篇关于2702. problem b的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!