首页 > 其他分享 >杜教筛入门

杜教筛入门

时间:2024-09-06 11:03:26浏览次数:6  
标签:phi ll 入门 epsilon sum 杜教 mu displaystyle

其实是因为莫反的题非常非常要用这个所以才来学。
有些莫反甚至要求灵活运用,而不只是求\(\sum\mu(n)\)和\(\sum\phi(n)\)

前置的芝士

狄利克雷卷积

对于两个数论函数\(f,g\),他们两个函数的前\(n\)项的狄利克雷卷积表示为\((f*g)(n)\),\((f*g)(n)=\displaystyle\sum_{d|n}f(d)g(\frac{n}{d})\)

显然狄利克雷卷积的运算满足交换律。同时满足结合律。

其单位元为\(\epsilon\),也就是满足\(f*\epsilon=f\),应该是很明显的吧。
额,\(\epsilon(n)=[n=1]\),还有后面会用到的\(I(n)=1\),\(id(n)=n\)

结合狄利克雷卷积能够得到一些非常非常有用的东西

1.\(\mu *I=\epsilon\)
2.\(\phi *I =id\)
3.\(\mu *id =\phi\)

这三个其实就分别对应了莫反最基础的三个公式
\(\epsilon(n)=\displaystyle\sum_{d|n}\mu(d) , n=\displaystyle\sum_{d|n}\phi(d) ,\sigma(n)=\displaystyle\sum_{d|n}d\)

后面推导的过程就会有体现。

莫比乌斯反演

若\(g(n)=\displaystyle\sum_{d|n}f(d)\),则有\(f(n)=\displaystyle\sum_{d|n}\mu(d)g(\frac{n}{d})\)
其实给出的条件就等价于\(g=f*I\),然后左右两边同时和\(\mu\)做卷积,得到\(g*\mu=f*I*\mu\),而根据上面所说的,\(I*\mu=\epsilon\)
所以能够得到\(g*\mu=f*\epsilon=f\),就是\(f(n)=\displaystyle\sum_{d|n}\mu(d)g(\frac{n}{d})\)

杜教筛

基本模型

考虑求一个积性函数\(f\)的前\(n\)项和\(S(n)=\displaystyle\sum_{i=1}^{n}f(i)\),设\(g\)为另一个积性函数
它们的狄利克雷卷积的前缀和为\(\displaystyle\sum_{i=1}^{n}(f*g)(i)=\displaystyle\sum_{i=1}^n\displaystyle\sum_{d|i}^{}f(d)g(\frac i d)\),然后是经典的反演思路,枚举\(d\)并且提前循环
得到\(\displaystyle\sum_{d=1}^nf(d)\displaystyle\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}g(i)=\displaystyle\sum_{d=1}^ng(d)\displaystyle\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}f(i)=\displaystyle\sum_{d=1}^ng(d)S({\lfloor\frac{n}{d}\rfloor})\)
而此时可以得到\(g(1)S(n)+\displaystyle\sum_{d=2}^ng(d)S({\lfloor\frac{n}{d}\rfloor})=\displaystyle\sum_{i=1}^n(f*g)(i)\)
再移项,就能够得到杜教筛的核心式子,\(g(1)S(n)=\displaystyle\sum_{i=1}^n(f*g)(i)-\displaystyle\sum_{d=2}^ng(d)S({\lfloor\frac{n}{d}\rfloor})\)

这个式子的作用在于,我们可以通过找到一个恰当的积性函数\(g\),使得\(\displaystyle\sum_{i=1}^n(f*g)(i)\)和\(\displaystyle\sum_{i=1}^n g\)能够被快速求解,我们便能够通过整数分块快速的得到\(S(n)\)的值,并且是在一个小于\(O(n)\)的时间复杂度内。

这个放一个伪代码来更好的展示思路。

ll Get_sum(int n)//用以计算某个积性函数f的前缀和
{
    ll ans=fg_sum(n)//快速计算(f*g)(i)的前缀和

    for(ll l=2,r;l<=n;l=r+1)//数论分块,因为后面的部分是使用数论分块求解的
    {
        r=n/(n/l);
        ans-=(g_sum(r)-g_sum(l-1))*(Get_sum(n/l));//就是公式
    }
    return ans;
}

可以用记忆化优化,还有一些其他细节需要加上来优化常数,比如先用普通线性筛法筛出前面一部分的函数值,以避免在n较小的部分多次递归导致效率降低

例题

luogu p4213

给定\(n\),求\(\sum \mu(i)\)和\(\sum \phi(i)\)

就是杜教筛最常用的两个板子,求欧拉函数和莫比乌斯函数
先考虑如何求\(\sum\mu(i)\),根据上面所说的性质,\(\mu * I =\epsilon\),需要\(\displaystyle\sum_{i=1}^n(f*g)(i)\)和\(\displaystyle\sum_{i=1}^n g\)能够被快速求解,\(\displaystyle\sum_{i=1}^n\epsilon\)和\(\displaystyle\sum_{i=1}^n I\)实在太明显,所以直接就取$f \(为\)\mu\(,\)g\(为\)I$

如何是如何求\(\sum\phi(i)\),和前面的差不多,只不过用的是\(\phi*I=id\),\(\displaystyle\sum_{i=1}^{n}id\)和\(\displaystyle\sum_{i=1}^{n}I\)也是非常好算,所以取\(f\)为\(\phi\),\(g\)为\(I\)

然后就是套上面的代码了,但是需要一点优化,否则常数还是在的,容易T。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline ll read(){
	ll a=0,b=1;char c=getchar();
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
	return a*b;
}
const ll N=5e6;
ll phi[N+1],prim[N+1],cnt,mu[N+1];
unordered_map<ll,ll> ans_mu,ans_phi;
ll vis[N+1];
ll Sum_mu(ll n)
{
	if(n<=N)return mu[n];
	if(ans_mu[n])return ans_mu[n];
	ll ans=1;
	for(ll l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans-=1LL*(r-l+1)*(Sum_mu(n/l));
	}
	return ans_mu[n]=ans;
}
ll Sum_phi(ll n)
{
	if(n<=N)return phi[n];
	if(ans_phi[n])return ans_phi[n];
	ll ans=(n+1)*(n)/2;
	for(ll l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans-=(r-l+1)*Sum_phi(n/l);
	}
	return ans_phi[n]=ans;
}
int main()
{
	mu[1]=phi[1]=1;//先用筛法算出较小的部分
	for(ll i=2;i<=N;i++)
	{
		if(vis[i]==0)prim[++cnt]=i,mu[i]=-1,phi[i]=i-1;
		for(ll j=1;j<=cnt&&prim[j]*i<=N;j++)
		{
			vis[prim[j]*i]=1;
			if(i%prim[j]==0)
			{
				phi[i*prim[j]]=phi[i]*prim[j];
				mu[i*prim[j]]=0;
				break;
			}
			phi[i*prim[j]]=phi[i]*phi[prim[j]];
			mu[i*prim[j]]=mu[i]*mu[prim[j]];
		}
	}
	for(ll i=1;i<=N;i++)mu[i]+=mu[i-1],phi[i]+=phi[i-1];
	ll T=read();
	while(T--)
	{
		ll n=read();
		cout<<Sum_phi(n)<<' '<<Sum_mu(n)<<endl;
	}
	return 0;
}

标签:phi,ll,入门,epsilon,sum,杜教,mu,displaystyle
From: https://www.cnblogs.com/HLZZPawa/p/18399837

相关文章

  • WebGL入门(031):EXT_frag_depth 简介、使用方法、示例代码
    还是大剑师兰特:曾是美国某知名大学计算机专业研究生,现为航空航海领域高级前端工程师;CSDN知名博主,GIS领域优质创作者,深耕openlayers、leaflet、mapbox、cesium,canvas,webgl,echarts等技术开发,欢迎加底部微信(gis-dajianshi),一起交流。No.内容链接1Openlayers【入门教程】-......
  • Claude的小白入门指南
    要想快速上手ClaudeAI,其实并没有那么复杂。作为新一代的AI助手,Claude致力于为用户提供高效、无害、透明的交互体验。这篇入门指南将从ClaudeAI的特点、主要功能和如何实际操作等几个方面为大家做一个详细的介绍。ClaudeAI是什么?Claude是由Anthropic开发的一款多功能AI......
  • 【Python篇】PyQt5 超详细教程——由入门到精通(中篇一)
    文章目录PyQt5入门级超详细教程前言第4部分:事件处理与信号槽机制4.1什么是信号与槽?4.2信号与槽的基本用法4.3信号与槽的基础示例代码详解:4.4处理不同的信号代码详解:4.5自定义信号与槽代码详解:4.6信号槽的高级用法4.7总结第5部分:文件对话框与文件处理5.1什么......
  • PYthon基础入门 day01——PYthon基础语法(上)
    目录一.注释二.语句结束符和分行符1.语句结束符2.分行符三.行和缩进四.变量及数据类型1.变量2.数据类型3.数字(Numbers)数据类型4.字符串(String)5.列表(List)6.元组(Tuple)7.字典(Dictionary)五.数据类型的转换六.标识符与关键字1.标识符2.关键字一.注释在PYthon中......
  • C++入门项目:Linux下C++轻量级Web服务器 跑通|运行|测试(小白进)
    TinyWebServer是一个开源的项目,适合小白入门C++网络编程,注意该项目是在linux系统下。Linux下C++轻量级Web服务器,助力初学者快速实践网络编程,搭建属于自己的服务器.使用线程池+非阻塞socket+epoll(ET和LT均实现)+事件处理(Reactor和Proactor均实现)的并发模型使用状......
  • 【C++初窥门庭】C++入门(二)
    目录一、 引用1.1引用概念6.2引用特性6.3常引用 6.4使用场景6.5传值、传引用效率比较6.6引用和指针的区别二、 内联函数2.1概念2.2特性三、auto关键字(C++11)3.1类型别名思考3.2auto简介3.3auto的使用细则 3.4 auto不能推导的场景 四、基于范......
  • Java入门笔记1(类和对象前)
    java中使用输入函数import  java.util.ScannerScannersrc=newScanner(System.in)输入两个数,使用方法返回两个数中的最大值importjava.util.Scanner;publicclassMain{publicstaticvoidmain(String[]args){Scannersc=newScanner(System.in);......
  • ctfshow-web入门-信息搜集(web1-web10)
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录web1(查看源代码)右击页面查看源代码web2(js前台拦截===无效操作)打开题目地址采用burp抓包并进行重发数据包web3(没思路的时候抓个包看看,可能会有意外收获)打开题目链接查看源码无果采用burp抓包并......
  • C++入门基础知识50——【关于C++数字】之C++ 数学运算
    成长路上不孤单......
  • 1.Javase入门基础
    Javase入门基础1.会常用的dos命令2.会安装java所需要的环境(jdk)3.会配置java的环境变量4.知道java开发三步骤5.会入门程序6.会三种注释方式7.Java入门程序所需要注意的地方8.println和print区别一、算机编程核心语法(固定格式)数据类型、运算符、流程控制、数组、方法二、面向对象核......