首页 > 编程语言 >算法进阶课

算法进阶课

时间:2022-12-06 20:13:02浏览次数:35  
标签:进阶 int 乌斯 sum 算法 莫比 我们 gcd

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

输入格式

第一行一个整数 n。

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

输出格式

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

数据范围

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

输入样例:

2
2 5 1 5 1
1 5 1 5 2

输出样例:

14
3

核心思路

莫比乌斯函数

首先我们需要了解莫比乌斯函数的基本定义:

还有就是怎么去求莫比乌斯函数,我们需要记住的是时刻从定义出发。然后接下来就是莫比乌斯的一个重要推导性质:

  1. n=1 \(\sum_{d|n}u(d)=1\)

  2. n!=1 \(\sum_{d|n}u(d)=0\)

下面是相关的证明:

假设\(n=\prod_{i=1}^{k} p_i^{c_i}\),\(n^{''}=\prod_{i=1}^{k} p_i\).

所以\(\sum_{d|n}u(d)=\sum_{d|n^{''}} u(d)=\sum_{i=0}^{k}C_{k}^{i}*(-1)^k\)

这个后面的主要是我们对于一个质因子的选择,比如选一个,选两个。然后对应的u(d)也要发生变化。然后第一个等于号怎么成立呢。因为d肯定是n的质因数。所以必然是可以成立的。

然后其实我们可以使用\(S(n)=\sum_{d|n} u(d)\),用通俗易懂的话解释就是\(S(n)\)是n中质因子的莫比乌斯函数的和.

  1. 当n=1时,\(S(n)=1\)

  2. 当n!=1时,\(S(n)=0\)


莫比乌斯反演


问题解决

然后我们这里有个重要的思想,那就是把我们的实际问题转换为对应的模型,也就是把那个实际问题给用F(n),f(n)表示出来。其中我们的F(n)可以表示为\(\sum_{i=1}^{a}\sum_{j=1}^{b}[n|(i,j)]\),\((i,j)\)表示的是gcd(i,j).F(n)的是实际意义就是i,j最大公约数是n的倍数的个数。所以我们f(n)就需要是\(\sum_{i=1}^{a}\sum_{j=1}^{b}gcd(i,j)\),这个我们可以根据莫比乌斯反演来验证其正确性。其实我们可以根据f(n)的实际意义来反推F(n)的表达式。

然后我们吧F(n)化简方便后面套用公式。

我们可以知道F(n)枚举的是gcd是n的倍数。而[1,a],n的倍数是n/a,[1,b]n的倍数是n/b;然后使用组合乘法:F(n)=\(\lfloor{n/a}\rfloor *\lfloor{n/b}\rfloor\).然后我们套用公式化简:

然后我们接下来的下取整就是数论分块的知识。不记得就去看数论的博客。所以我们知道a'/d’在[l,r]中的值不变,所以我们才需要求u(x)的前缀和,方便计算。

接下来就还有一个二维前缀和的知识点,因为我们需要在x和y在一定的范围内取点。所以可以具化为这个图像:

我们要注意为什么我们又会想到面积呢,其实是因为\(\sum_{i=1}^{a} \sum_{j=1}^{b}\)表示的本来就是二重积分,而我们二重积分的集合意义就是面积。然后把这个面积表示出来就好了。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int primes[N], st[N];
int mobius[N],sum[N];
int cnt;
void Init()
{
    mobius[1]=1;//这个初始化一定需要主意啊
	for (int i = 2;i < N;i++)
	{
		if (st[i] == 0)
		{
			primes[cnt++] = i;
			mobius[i] = -1;//因为这是一个单纯的质数。没有任何质因子
		}
		for(int j=0;primes[j]*i<N;j++)
		{
			st[i * primes[j]] = 1;
			int t = i * primes[j];
			if (i % primes[j] == 0)
			{
				mobius[t] = 0;//因为这个说明至少包含两个primes[j]
				break;
			}
			mobius[t] = -mobius[i];//这个因为我们加入了一个系数为1的质因子
		}
	}
	for (int i = 1;i < N;i++)
		sum[i] = sum[i - 1] + mobius[i];
}
int get(int a, int k)
{
	return a / (a / k);
}
LL f(int a, int b, int k)
{
	a = a / k, b = b / k;
	LL res = 0;
	int n = min(a, b);
	for (int l = 1, r;l <= n;l = r + 1)
	{
		r = min(n, min(get(a, l), get(b, l)));
		res += (LL)(sum[r] - sum[l - 1]) * (a / l) * (b / l);
	}
	return res;
}
int main()
{
	int T;
	cin >> T;
	Init();
	while (T--)
	{
		int a, b, c, d, k;
		cin >> a >> b >> c >> d >> k;
		cout << f(b, d, k) - f(a-1, d, k) - f(b, c-1, k) + f(a - 1, c - 1, k) << endl;
	}
}

标签:进阶,int,乌斯,sum,算法,莫比,我们,gcd
From: https://www.cnblogs.com/xyh-hnust666/p/16960374.html

相关文章

  • BFPRT算法(TOP-K问题)
    一:背景介绍在一大堆数中求其前k大或前k小的问题,简称TOP-K问题。而目前解决TOP-K问题最有效的算法即是BFPRT算法,其又称为中位数的中位数算法,该算法由Blum、Floyd、Pratt、Riv......
  • 算法复杂度分析概要
    一:渐近符号1.1符号的辨析1.1.1符号OO,读作“大O”,非正式来说,O(g(n))是增长次数小于等于g(n)及其常数倍(n趋向于无穷大)的函数集合。  定义如果函数f(n)包含在O(g(n))中,......
  • 面试算法题
    小球高处落下回弹运动距离"""一个小球从100m高度落下,每次弹回原高度一半.计算:--总共弹起多少次?(最小弹起高度0.01m)13次--全过程总共移动......
  • Vue的keep-alive、虚拟DOM的作用、diff算法
    一、keep-alive作用:keep-alive标签是vue的内置标签,可在组件切换过程中将状态保留在内存中,防止DOM重复渲染。标签属性:include:符合条件的组件会被缓存,exclude:符合条件的组......
  • 朴素贝叶斯算法
    一,朴素贝叶斯算法理论基础朴素贝叶斯算法是基于贝叶斯定理与特征条件独立假设的分类方法。对于给定的训练集,首先基于特征条件独立假设学习输入输出的联合概率分布(朴素贝叶......
  • 每日算法之二叉树中和为某一值的路径(二)
    JZ34二叉树中和为某一值的路径(二)描述输入一颗二叉树的根节点root和一个整数expectNumber,找出二叉树中结点值的和为expectNumber的所有路径。1.该题路径定义为从树的......
  • 二叉树入门到进阶(下一篇讲红黑树)——c语言刷题合集
    目录二叉树概念二叉树的遍历方式DFS(前序中序后序遍历)144.二叉树的前序遍历递归解法迭代解法94.二叉树的中序遍历145.二叉树的后序遍历层序遍历--队列的作用102.二叉......
  • Go-09 Go语言中数组、切片的排序算法以及sort包
    packagemainimport( "fmt" "sort")//Golang数组中的切片及sort包funcmain(){ //1.选择排序 varnumSlice=[]int{9,8,7,6,5,4} fori:=0;i<le......
  • 初识Linux(十一)------ 磁盘配额与进阶文件系统管理
      如果Linux服务器有多个用户经常存取数据时,为了维护所有使用者在硬盘容量的公平使用,磁盘配额(Quota)就是一项非常有用的工具。另外,如果磁盘容量不够用,那么更进阶的文件......
  • 字节二面,居然让我写一个 LFU 缓存策略算法,懵了!
    LRU全称"LeastRecentlyUsed",最近最少使用策略,判断最近被使用的时间,距离目前最远的数据优先被淘汰,作为一种根据访问时间来更改链表顺序从而实现缓存淘汰的算法,它是redis......