【数论】莫比乌斯反演(欧拉反演)进阶-杜教筛

news2024/11/26 2:51:08

文章目录

      • 前言
    • 回忆
  • 题集
    • 1
    • 2
  • 杜教筛
    • 例题

前言

这里需要对莫反有一些基础
不会的可以点这里

回忆

  • f ( n ) = ∑ d ∣ n g ( d ) → g ( n ) = ∑ d ∣ n f ( d ) μ ( n d ) f(n)=\sum_{d|n}g(d)\rightarrow g(n)=\sum_{d|n}f(d)\mu(\frac{n}{d}) f(n)=dng(d)g(n)=dnf(d)μ(dn)
  • ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n}\mu(d)=[n=1] dnμ(d)=[n=1]
  • ∑ i = 1 n ⌊ n i ⌋ = \sum_{i=1}^n\left\lfloor\frac{n}{i}\right\rfloor= i=1nin= 你应该知道怎么求
  • ∑ i = 1 1 0 9 μ ( i ) = \sum_{i=1}^{10^9}\mu(i)= i=1109μ(i)= 你可能需要知道怎么求
  • 线性筛 μ ( i ) , φ ( i ) \mu(i),\varphi(i) μ(i),φ(i)
  • 一些数学能力

题集

1

∏ i = 1 n ∏ j = 1 m gcd ⁡ ( i , j ) \large\prod_{i=1}^n\prod_{j=1}^m\gcd(i,j) i=1nj=1mgcd(i,j)
= ∏ d = 1 d ∑ i = 1 ∑ j = 1 m [ gcd ⁡ ( i , j ) = d ] =\prod_{d=1}d^{\sum_{i=1}\sum_{j=1}^m[\gcd(i,j)=d]} =d=1di=1j=1m[gcd(i,j)=d]
= ∏ d = 1 d ∑ k = 1 min ⁡ ( n , m ) d μ ( k ) n k d m k d =\prod_{d=1}d^{\sum_{k=1}^\frac{\min(n,m)}{d}\mu(k)\frac{n}{kd}\frac{m}{kd}} =d=1dk=1dmin(n,m)μ(k)kdnkdm
= ∏ T = 1 ( ∏ k ∣ T ( T k ) μ ( k ) ) n T m T =\prod_{T=1}(\prod_{k|T}(\frac{T}{k})^{\mu(k)})^{\frac{n}{T}\frac{m}{T}} =T=1(kT(kT)μ(k))TnTm
f ( T ) = ∏ k ∣ T ( T k ) μ ( k ) f(T)=\prod_{k|T}(\frac{T}{k})^{\mu(k)} f(T)=kT(kT)μ(k)
线性筛+整出分块即可
Code:

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
#define cou(i) cout<<fixed<<setprecision(i)
using namespace std;
const int N=1e7+1,mod=1e9+7;
int t,n,m,k,ans,res;
unordered_map<int,int>Mu;
struct fy{
	int prv[N],cnt,mu[N],F[N];
	bool pr[N];
	int qmi(int x,int y){
		int res=1;
		while(y>0){
			if(y&1)
				res=res*x%mod;
			x=x*x%mod,y>>=1;
		}
		return res;
	}
	void ola(int x){
		pr[1]=mu[1]=F[1]=1;
		for(int i=2;i<=x;i++){
			if(!pr[i])
				prv[++cnt]=i,mu[i]=-1,F[i]=i;
			for(int j=1;j<=cnt&&i*prv[j]<=x;j++){
				int u=i*prv[j];
				pr[u]=1;
				if(i%prv[j]==0){
					mu[u]=0;
					F[u]=F[i];
					break;
				}
				else{
					mu[u]=-mu[i];
					F[u]=1;
				}
			}
		}
	}
	void getsum(int x){
		F[0]=1;
		for(int i=1;i<=x;i++){
			F[i]*=F[i-1],F[i]%=mod; 
		}
	}
	int summu(int x){
		int res=1;
		if(x<N)
			return mu[x];
		if(Mu[x])
			return Mu[x];
		for(int l=2,r;l<=x;l=r+1){
			r=x/(x/l);
			res-=(summu(x/l))*(r-l+1);
		}
		Mu[x]=res;
		return res;
	}
	int sumphi(int x){
		int res=0;
		for(int l=1,r;l<=x;l=r+1){
			r=x/(x/l);
			res+=(summu(r)-summu(l-1))*(x/l)*(x/l);
		}
		return res;
	}
}A;
signed main(){
	IOS;
	A.ola(N-1);
	A.getsum(N-1);
	cin>>t;
	while(t--){
		cin>>n>>m;
		int ans=1ll;
		for(int l=1,r;l<=min(n,m);l=r+1){
			r=min(n/(n/l),m/(m/l));
			int res=A.F[r]*A.qmi(A.F[l-1],mod-2)%mod;
			ans=ans*A.qmi(res,(n/l)*(m/l))%mod;
		}
		cout<<ans<<"\n";
	}
	return 0;
}

经验:
1
2
3

2

Link
在这里插入图片描述
暴力推式子。
关键:
gcd ⁡ ( i j , j k , k i ) = gcd ⁡ ( i , j ) gcd ⁡ ( j , k ) gcd ⁡ ( k , i ) gcd ⁡ ( i , j , k ) \large{\gcd(ij,jk,ki)=\frac{\gcd(i,j)\gcd(j,k)\gcd(k,i)}{\gcd(i,j,k)}} gcd(ij,jk,ki)=gcd(i,j,k)gcd(i,j)gcd(j,k)gcd(k,i)
然后可得原式=于神之怒加强版或这里
好像这黑题有那么一点点水啊
Code:

#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false),cin.tie(NULL),cout.tie(NULL)
using namespace std;
const int N=2e7+1,mod=1e9+7;
int t,n,m,p,k;
struct fy{
	int prv[N],cnt,g[N],s[N];
	bool pr[N];
	inline int qmi(int x,int y){
		int res=1;
		while(y>0){
			if(y&1)
				res=res*x%mod;
			x=x*x%mod,y>>=1;
		}
		return res;
	}
	void ola(int x){
		pr[1]=g[1]=1;
		for(int i=2;i<=x;i++){
			if(!pr[i])
				prv[++cnt]=i,g[i]=(qmi(i,k)-1+mod)%mod;
			for(int j=1;j<=cnt&&i*prv[j]<=x;j++){
				int u=i*prv[j];
				pr[u]=1;
				if(i%prv[j]==0){
					g[u]=g[i]*qmi(prv[j],k)%mod;
					break;
				}
				else{
					g[u]=g[i]*g[prv[j]]%mod;
				}
			}
		}
	}
	void getsum(int x){
		for(int i=1;i<=x;i++)
			g[i]=(g[i]+g[i-1])%mod;
	}
}A;
signed main(){
	IOS;
	k=2;
	cin>>t;
	A.ola(N-1);
	A.getsum(N-1);
	while(t--){
		cin>>n>>m>>p;
		int ans=0,res=0;
		for(int l=1,r;l<=min(n,m);l=r+1){
			r=min(n/(n/l),m/(m/l));
			res+=(n/l)*(m/l)%mod*((A.g[r]-A.g[l-1]+mod)%mod)%mod;
			res%=mod;
		}
		ans+=res*p;
		ans%=mod;
		res=0;
		for(int l=1,r;l<=min(m,p);l=r+1){
			r=min(m/(m/l),p/(p/l));
			res+=(m/l)*(p/l)%mod*((A.g[r]-A.g[l-1]+mod)%mod)%mod;
			res%=mod;
		}
		ans+=res*n;
		ans%=mod;
		res=0;
		for(int l=1,r;l<=min(p,n);l=r+1){
			r=min(p/(p/l),n/(n/l));
			res+=(p/l)*(n/l)%mod*((A.g[r]-A.g[l-1]+mod)%mod)%mod;
			res%=mod;
		}
		ans+=res*m;
		ans%=mod;
		cout<<ans<<"\n";
	}
	return 0;
}

杜教筛

来自 OI-wiki的资料:

这里直达

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里直达OI-wiki


例题

给定一个正整数,求
a n s 1 = ∑ i = 1 n φ ( i ) , a n s 2 = ∑ i = 1 n μ ( i ) ans_1=\sum_{i=1}^n\varphi(i),ans_2=\sum_{i=1}^n \mu(i) ans1=i=1nφ(i),ans2=i=1nμ(i)
输入的第一行为一个整数,表示数据组数 T T T
接下来 T T T 行,每行一个整数 n n n,表示一组询问。
对于每组询问,输出一行两个整数,分别代表 a n s 1 ans_1 ans1 a n s 2 ans_2 ans2
对于全部的测试点,保证 1 ≤ T ≤ 10 1 \leq T \leq 10 1T10 1 ≤ n < 2 31 1 \leq n \lt 2^{31} 1n<231
考虑使用杜教筛。
S 1 ( n ) = ∑ i = 1 n μ ( i ) S_1(n)=\sum_{i=1}^n\mu(i) S1(n)=i=1nμ(i)
在这里插入图片描述
在这里插入图片描述
那样我们就完成了两个最简单的例题了
Code:

#include<bits/stdc++.h>
#define int __int128
using namespace std;
const int N=2e6+1,mod=1e9+7;
int t,n,m,k;
void write(int x){
	if(x<0)
		putchar('-'),x=-x;
	if(x>=10)
		write((int)(x/10));
	char o='0'+x%10;
	putchar(o);
}
void read(int &x){
	x=0;
	int y=1;
	char c=getchar();
	while(c>'9'||c<'0'){
		if(c=='-'){
			y=-1;
			break;
		}
		c=getchar();
	}
	while(c<='9'&&c>='0')
		x=x*10+c-'0',c=getchar();
	x*=y;
}
map<int,int>Mu,Phi;
struct fy{
	int prv[N],cnt,phi[N],mu[N];
	bool pr[N];
	void ola(int x){
		pr[1]=mu[1]=1;
		for(int i=2;i<=x;i++){
			if(!pr[i])
				prv[++cnt]=i,mu[i]=-1;
			for(int j=1;j<=cnt&&i*prv[j]<=x;j++){
				int u=i*prv[j];
				pr[u]=1;
				if(i%prv[j]==0){
					mu[u]=0;
					break;
				}
				else{
					mu[u]=-mu[i];
				}
			}
		}
	}
	void getsumF(int x){
		for(int i=1;i<=x;i++)
			mu[i]+=mu[i-1];
	}
	int summu(int x){
		int res=1;
		if(x<N)
			return mu[x];
		if(Mu[x])
			return Mu[x];
		for(int l=2,r;l<=x;l=r+1){
			r=x/(x/l);
			res-=(summu(x/l))*(r-l+1);
		}
		Mu[x]=res;
		return res;
	}
	int sumphi(int x){
		int res=0;
		for(int l=1,r;l<=x;l=r+1){
			r=x/(x/l);
			res+=(summu(r)-summu(l-1))*(n/l)*(n/l);
		}
		return res;
	}
}A;
signed main(){
	A.ola(N-1);
	A.getsumF(N-1);
	read(t);
	while(t--){
		read(n);
		write((A.sumphi(n)-1)/2+1);
		putchar(' ');
		write(A.summu(n));
		putchar('\n');
	}
	return 0;
}
//此代码有一点瑕疵,但确实可以过模板题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1565511.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3+eachrts饼图轮流切换显示高亮数据

<template><div class"charts-box"><div class"charts-instance" ref"chartRef"></div>// 自定义legend 样式<div class"charts-note"><span v-for"(items, index) in data.dataList" cla…

unity之 “Allow ‘unsafe‘ code“ 在哪里。

导入unity中的代码&#xff0c;出现如下错误&#xff0c;该如何解决&#xff1f; Unsafe code may only appear if compiling with /unsafe. Enable "Allow unsafe code" in Player Settings to fix this error 解决这个问题&#xff0c;只需要设置就可以。 设置的地…

【苍穹外卖】log爆红

使用了Slf4j注解&#xff0c;用于自动生成一个log对象&#xff0c;相当于private final Logger log LoggerFactory.getLogger(当前类名.class); 这个注解需要安装Lombok插件才能使用。 IDEA file—settings–plugins&#xff0c;搜索lombok–install。安装完后自动重启IDEA后…

【WEEK6】 【DAY2】DQL Data Querying - Part Two 【English Version】

2024.4.2 Tuesday Following the previous article 【WEEK6】 【DAY1】DQL Data Query - Part One【English Version】 Contents 4.4. Join Queries4.4.1. JOIN Comparison4.4.2. Seven Types of JOINs4.4.3. Examples4.4.3.1. In this example, the results of INNER JOIN and…

DLL导出API注意事项

文章目录 问题原则示例一解决方案 示例二解决方法 参考 问题 在 windows 平台下&#xff0c;如果在动态库的接口中使用 std::string 或其它 std 容器&#xff0c;会导致崩溃或其它内存问题&#xff0c;所以一般要求动态库的接口必须是 C 语言实现。 原则 一个原则&#xff1a;…

LabVIEW专栏二、调用子VI

该节目标是创建带子vi&#xff0c;修改vi属性&#xff0c;测试可重入和不可重入的区别 一 、设置子VI 把VI封装成为子VI&#xff0c;可以帮助模块化程序&#xff0c;简化代码结构。 任何VI本身都可以成为别的VI的子VI。 1.1、设置输入输出端子 1、在前面板空白处&#xff0…

JavaScript中什么叫深拷贝?

在 JavaScript 中&#xff0c;深拷贝指的是创建一个新的对象&#xff0c;这个新的对象与原始对象完全独立&#xff0c;没有任何共享的属性或者数据&#xff0c;它们不共享同一块内存地址。深拷贝会复制原始对象的所有属性和嵌套对象的所有属性&#xff0c;包括嵌套对象中的属性…

Mybatis——查询数据

查询操作 根据用户id查询单条记录&#xff0c;在映射器接口(UserMapper)中定义如下方法&#xff1a; package org.example.mapper;import org.example.demo.User;import java.util.List;public interface UserMapper {//根据id查询UserUser selectUserById(Integer userId); …

使用 RisingWave、NATS JetStream 和 Superset 进行实时物联网监控

在物联网&#xff08;IoT&#xff09;背景下&#xff0c;处理实时数据会遇到一些特定的障碍&#xff0c;如边缘计算资源不足、网络条件限制、扩展性存在问题、设备间有多样性差异。要克服这些挑战&#xff0c;需要高效的边缘计算技术、强大的安全措施、标准化协议、可扩展的管理…

【升降自如】OLED升降透明屏,智能调节,打造个性化观影体验

OLED升降透明屏&#xff0c;作为科技领域的创新之作&#xff0c;以其升降自如、智能调节的特点&#xff0c;为用户带来了前所未有的个性化观影体验。 这款透明屏采用先进的OLED显示技术&#xff0c;不仅色彩鲜艳、对比度高&#xff0c;而且具备出色的透明性能。更值得一提的是&…

3D人脸扫描技术与数字人深度定制服务:赋能打造超写实3D数字分身

在数字时代&#xff0c;3D数字分身有着广泛的应用场景&#xff0c;在动画视频、广告宣传片、大型活动主持人、AI交互数字人等领域&#xff0c;发挥着重要的商业价值。其中&#xff0c;3D人脸扫描技术&#xff0c;推动了超写实3D数字分身的诞生。 公司案例 2023海心沙元宇宙音乐…

10_MVC

文章目录 JSON常用的JSON解析Jackson的常规使用指定日期格式 MVC设计模式MVC介绍前后端分离案例&#xff08;开发与Json相关接口&#xff09; 三层架构三层架构介绍 JSON JSON&#xff08;JavaScript Object Notation&#xff09; 是一种轻量级的数据交换格式&#xff0c;是存…

[中级]软考_软件设计_计算机组成与体系结构_06_ 流水线技术

流水线技术 前言相关考试考点一&#xff1a;流水线执行时间概念流水线步骤解析参数计算案例解析&#xff1a;流水线计算第一问第二问 考点二&#xff1a;流水线吞吐率 前言 第一章比较重要的一种计算题型&#xff0c;经常考到&#xff0c;一般考试1 ~ 2分。 相关考试 流水线…

【智能算法】蜜獾算法(HBA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2021年&#xff0c;FA Hashim等人受到自然界中蜜獾狩猎行为启发&#xff0c;提出了蜜獾算法&#xff08;(Honey Badger Algorithm&#xff0c;HBA&#xff09;。 2.算法原理 2.1算法思想 蜜獾以其…

文献速递:深度学习胰腺癌诊断--深度学习算法用于从疾病轨迹预测胰腺癌风险

文献速递&#xff1a;深度学习胰腺癌诊断--深度学习算法用于从疾病轨迹预测胰腺癌风险 麦田医学 美好事物中转站 2024-04-02 14:36 Title 题目 A deep learning algorithm to predict risk of pancreatic cancer from disease trajectories 深度学习算法用于从疾病轨迹预测…

WPF-基础及进阶扩展合集(持续更新)

目录 一、基础 1、GridSplitter分割线 2、x:static访问资源文件 3、wpf触发器 4、添加xaml资源文件 5、Convert转换器 6、多路绑定与多路转换器 二、进阶扩展 1、HierarchicalDataTemplate 2、XmlDataProvider从外部文件获取源 3、TextBox在CellTemplate中的焦点问题…

【LeetCode热题100】79. 单词搜索(回溯)

一.题目要求 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 单词必须按照字母顺序&#xff0c;通过相邻的单元格内的字母构成&#xff0c;其中“相邻”单元格是那些水平…

揭秘代码安全:告别硬编码,灵活策略守护你的账户密码信息安全

前言 在编写代码时&#xff0c;为了遵循严格的安全规范&#xff0c;应避免硬编码任何敏感信息如账号凭证、密钥等直接出现在源代码中。相反&#xff0c;推荐采取安全措施&#xff0c;如使用环境变量、加密存储或安全凭据管理系统来间接引用和保护这类数据。如此一来&#xff0c…

使用 Docker 部署 Puter 云桌面系统

1&#xff09;Puter 介绍 :::info GitHub&#xff1a;https://github.com/HeyPuter/puter ::: Puter 是一个先进的开源桌面环境&#xff0c;运行在浏览器中&#xff0c;旨在具备丰富的功能、异常快速和高度可扩展性。它可以用于构建远程桌面环境&#xff0c;也可以作为云存储服…

c++对象指针

对象指针在使用之前必须先进行初始化。可以让它指向一个已定义的对象&#xff0c;也可以用new运算符动态建立堆对象。 定义对象指针的格式为&#xff1a; 类名 *对象指针 &对象; //或者 类名 *对象指针 new 类名(参数); 用对象指针访问对象数据成员的格式为&#xff1a…