首页 > 其他分享 >杜教筛学习笔记

杜教筛学习笔记

时间:2023-07-30 15:55:31浏览次数:32  
标签:right frac limits cdot sum 笔记 杜教 学习 left

杜教筛

杜教筛的基本形式

对于积性函数\(g(n)\)我们希望求他的前缀和\(S_g(n)\),如果有另一积性函数\(f(n)\)满足\(f*g=h\),且\(fh\)的前缀和易求,那么我们可以通过\(S_f(n) S_h(n)\)快速的求出\(S_g(n)\)。

\[\begin{aligned} S_h(n)&=\sum\limits_{i=1}^n\sum\limits_{d|i}f(d)\cdot g(\frac{n}{d})\\ &=\sum\limits_{d=1}^n\sum\limits_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor}f(d)\cdot g(i)\\ &=\sum\limits_{d=1}^nf(d)\cdot S_g\left( \left\lfloor \frac{n}{d} \right\rfloor \right)\\ S_g(n)&=S_h(n)-\sum\limits_{d=2}^nf(d)\cdot S_g\left( \left\lfloor \frac{n}{d} \right\rfloor \right) \end{aligned} \]

对后面的\(S_g\left( \left\lfloor \frac{n}{d} \right\rfloor \right)\)进行数论分块就可以更快速的求出\(g\)的前缀和。

时间复杂度分析:

在求解过程中我们只需要关注\(S_g\)在\(\left\{ \left\lfloor \frac{n}{k} \right\rfloor|k\subseteq \mathbb{N}^* \right\}\)处的取值,这部分一共只有\(O\left( \sqrt{n} \right)\)种取值,因此整个时间复杂度是:

\[\begin{aligned} &\sum\limits_{i=1}^{\sqrt{n}}O(\sqrt{i})+\sum\limits_{i=1}^{\sqrt{n}}O(\sqrt{\frac{n}{i}})\ge \int_0^{\sqrt{n}}\left( \sqrt{x}+\sqrt{\frac{n}{x}}\right) dx=O\left( n^{\frac{3}{4}} \right)\\ &\sum\limits_{i=1}^{\sqrt{n}}O(\sqrt{i})+\sum\limits_{i=1}^{\sqrt{n}}O(\sqrt{\frac{n}{i}})\leq \sqrt{n}\cdot 2\cdot \sqrt{\sqrt{i}\cdot \sqrt{\frac{n}{i}}}=O\left( n^{\frac{3}{4}} \right) \end{aligned} \]

通过上面的分析我们可以知道杜教筛的时间复杂度是\(O\left( n^{\frac{3}{4}} \right)\)

如果能预处理出前\(n^{\frac{2}{3}}\)项的前缀和,复杂度可以优化到\(O\left( n^{\frac{2}{3}} \right)\)

一些例子:

  • \(\mu\)的前缀和,有\(\mu*I=e\)
    所以,\(S_\mu(n)=1-\sum\limits_{i=2}^nS_\mu\left( \left\lfloor \frac{n}{i} \right\rfloor\right)\)

  • \(\varphi\)的前缀和,有\(\varphi*I=id\)
    所以,\(S_\varphi(n)=\frac{n\cdot (n+1)}{2}-\sum\limits_{i=2}^nS_\varphi\left( \left\lfloor \frac{n}{i} \right\rfloor\right)\)

贝尔级数

我们发现如果要用杜教筛求解积性函数前缀和问题,如何构造合适的狄利克雷卷积式子是很重要的一环,贝尔级数就是一个强有力的构造工具。

对于积性函数我们重点关注其在质数的幂处的取值,积性函数\(f(n)\)在质数\(p\)处的贝尔级数定义为\(F_p(x)=\sum\limits_{i=0}^{\infty}f(p^i)x^i\)

然后数论函数的狄利克雷卷积就可以变成一般多项式的卷积:

\[h=f*g\Leftrightarrow H_p(x)=\sum\limits_{i=0}^{\infty}h(p^i)x^i=\sum\limits_{i=0}^{\infty}\sum\limits_{k=0}^if(p^k)\cdot x^k\cdot g(p^{i-k})\cdot x^{i-k}=G_p(x)*F_p(x) \]

一些常见积性函数的贝尔级数:

  • \(e\rightarrow 1\)
  • \(I\rightarrow \sum\limits_{i=0}^{\infty}x^i=\frac{1}{1-x}\)
  • \(id\rightarrow\sum\limits_{i=0}^{\infty}p^i\cdot x^i=\frac{1}{1-p\cdot x}\)
  • \(id_k\rightarrow\sum\limits_{i=0}^{\infty}p^{k\cdot i}\cdot x^i=\frac{1}{1-p^k\cdot x}\)
  • \(\mu\rightarrow\sum\limits_{i=0}^{\infty}\mu\left( p^i \right) \cdot x^i=1-x\)
  • \(\varphi\rightarrow 1+\sum\limits_{i=1}^{\infty}p^{i-1}\cdot (p-1)\cdot x^i=1+\frac{p-1}{p}\cdot\sum\limits_{i=1}^{\infty}p^i\cdot x^i=\frac{1-x}{1-p\cdot x}\)

一些例子:

  • 求积性函数\(f(p^k)=p^k+[k>0]\cdot (-1)^k\)的前缀和。

    \[\begin{aligned} &先写出f的贝尔级数F_p(x)=1+\sum\limits_{i=1}^{\infty}(p^i+(-1)^i)\cdot x^i=\frac{1+p\cdot x^2}{(1-p\cdot x)\cdot (1+x)}\\ &F_p(x)*(1-p\cdot x)\cdot (1+x)=1+p\cdot x^2,其中(1-p\cdot x)对应\mu\cdot id(点乘)(1+x)对应\mu\cdot \mu\\ &1+p\cdot x^2对应的函数满足h(n)=[\exists d,n=d^2 \wedge\mu^2(\sqrt{n})=1]\cdot \sqrt{n}\\ &令g(n)=(\mu\cdot \mu)*(\mu\cdot id),则S_f(n)=S_h(n)-\sum\limits_{d=2}^ng(d)\cdot S_f\left( \left\lfloor \frac{n}{d} \right\rfloor \right)\\ &\sum\limits_{i=1}^nh(i)=\sum\limits_{i=1}^{\sqrt{n}}i\cdot \mu^2(i)\\ &现在需要求g(n)的前缀和,注意到(1-p\cdot x)\cdot (1+x)\cdot \frac{1}{1-px}=1+x\\ &S_g(n)=S_{\mu\cdot \mu}(n)-\sum\limits_{d=2}^n \frac{d\cdot (d+1)}{2}\cdot S_g(\left\lfloor \frac{n}{d} \right\rfloor)\\ &然后需要求\mu\cdot \mu 的前缀和\\ &(\mu\cdot \mu)(n)=[n的最大平方因子=1]=\sum\limits_{d|n的最大平方因子}\mu(d)=\sum\limits_{d^2|n}\mu(d)\\ &S_{\mu\cdot \mu}(n)=\sum\limits_{i=1}^n\sum\limits_{d^2|i}\mu(d)=\sum\limits_{d=1}^{\sqrt{n}}\mu(d)\cdot \left\lfloor \frac{n}{d^2} \right\rfloor \end{aligned} \]

Powerful Number

PN的定义是不含有次数为\(1\)的质因子的正整数。即考虑正整数\(n\)的标准分解形式\(n=\prod\limits_{i=1}^{k} p_i^{a_i} ,\forall i{\kern 3pt}a_i\ge 2\)

这种形式的正整数一定可以写成\(a^2\cdot b^3\),所以我们可以大概估计一下PN的数量,在\(\int_1^{\sqrt{n}}\sqrt[3]{\frac{n}{x^2}}dx=O\left( \sqrt{n} \right)\)级别。这样的性质会给求一些积性函数的前缀和带来便利。

假设我们要求积性函数\(f(n)\)的前缀和,我们可以先构造一个新的积性函数\(g(n)\)满足\(\forall p \subseteq prime,f(p)=g(p)\)。

此时必然存在一个积性函数\(h(n)\)满足\(f=g*h\)对于\(\forall p \subseteq prime,f(p)=g(1)\cdot h(p)+g(p)\cdot h(1)=h(p)+g(p)\)

而根据\(g\)的构造我们可以得出\(\forall p \subseteq prime,h(p)=0\)也就是说\(h\)只在PN处对答案有贡献,而PN的数量只有\(O\left( \sqrt{n} \right)\)!

\[S_f(n)=\sum\limits_{i=1}^{n}\sum\limits_{d|i}g(d)\cdot h(\frac{i}{d})=\sum\limits_{d=1}^nh(d)\cdot S_g(\left\lfloor \frac{n}{d} \right\rfloor)=\sum\limits_{d \subseteq PN}h(d)\cdot S_g(\left\lfloor \frac{n}{d} \right\rfloor) \]

接下来只需要求解\(h\)在PN处的取值,\(S_g\)可以用杜教筛计算。

考虑积性函数的取值只需要考虑其在质数的幂次处的取值:

\[f(p^k)=\sum\limits_{i=0}^kg(p^i)\cdot h(p^{k-i})\Rightarrow h(p^k)=f(p^k)-\sum\limits_{i=1}^{k}g(p^i)\cdot h(p^{k-i}) \]

由于是PN这里只需要考虑小于\(\sqrt{n}\)的质数,这部分暴力计算即可。

例子:定义积性函数\(f(p^k)=p^k\cdot (p^k-1)\quad p \subseteq prime\)求\(S_f(n)\)。

构造\(g(n)=n\cdot \varphi(n)\)有\(g(p)=p\cdot (p-1)=f(p)\quad p \subseteq prime\)

写出\(g\)的贝尔级数\(1+\sum\limits_{i=1}^{\infty}p^i\cdot p^{i-1}\cdot (p-1)\cdot x^i=\frac{1-p\cdot x}{1-p^2\cdot x}\)

注意到\(g*id=id_2\),所以\(S_g(n)=\frac{n\cdot (n+1)\cdot (2\cdot n+1)}{6}-\sum\limits_{d=2}^n \frac{n\cdot (n+1)}{2}\cdot S_g(\left\lfloor \frac{n}{d} \right\rfloor)\)

对于\(h\)的PN部分暴力计算。

code:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define int long long

using namespace std;

const int mo = 1e9 + 7;
const int inv2 = (mo + 1) >> 1;
const int inv3 = (mo + 1) / 3;
const int inv6 = 1ll * inv2 * inv3 % mo;

int prime[200005], cnt = 0, g[2000005], n, sum[100005], ans = 0;
bool a[2000005];
vector<int> h[10005];

int mi(int o, int p) {
    int yu = 1;
    while (p) {
        if (p & 1) yu = 1ll * yu * o % mo;
        o = 1ll * o * o % mo;
        p >>= 1;
    }
    return yu;
}

int S(int N) { return 1ll * N % mo * (N % mo + 1) % mo * inv2 % mo; }

int cal(int N) {
    if (N <= 2000000) return g[N];
    if (sum[n / N] != -1) return sum[n / N];
    int yu = 1ll * N % mo * (N % mo + 1) % mo * ((N + N) % mo + 1) % mo;
    yu = 1ll * yu * inv6 % mo;
    for (int l = 2, r; l <= N; l = r + 1) {
        r = N / (N / l);
        yu -= 1ll * (S(r) - S(l - 1)) * cal(N / l) % mo;
        yu = (yu % mo + mo) % mo;
    }
    return sum[n / N] = yu;
}

void dfs(int o, int p, int q) {
    ans = (ans + 1ll * q * cal(n / o) % mo) % mo;
    for (int tt = p; tt <= cnt; tt++) {
        if (n / o < prime[tt] * prime[tt]) break;
        int yu = o * prime[tt] * prime[tt];
        for (int t = 2; yu <= n; yu *= prime[tt], t++) {
            dfs(yu, tt + 1, 1ll * q * h[tt][t] % mo);
        }
    }
}

signed main() {
    memset(sum, -1, sizeof(sum));
    for (int i = 2; i <= 2000000; i++) {
        if (!a[i]) {
            prime[++cnt] = i;
            g[i] = 1ll * i * (i - 1) % mo;
        }
        for (int j = 1; j <= cnt && i * prime[j] <= 2000000; j++) {
            a[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                g[i * prime[j]] = 1ll * g[i] * prime[j] % mo * prime[j] % mo;
                break;
            }
            g[i * prime[j]] = 1ll * g[i] * prime[j] % mo * (prime[j] - 1) % mo;
        }
    }
    g[1] = 1;
    for (int i = 2; i <= 2000000; i++) {
        g[i] = (g[i - 1] + g[i]) % mo;
    }
    scanf("%lld", &n);
    for (int i = 1; i <= cnt; i++) {
        if (prime[i] > 100000) break;
        h[i].push_back(1);
        for (int j = prime[i], k = 1; j <= n; j *= prime[i], k++) {
            int yu = 1ll * j % mo * (j % mo - 1) % mo;
            for (int s = 0; s < k; s++) {
                yu -= 1ll * h[i][s] * mi(prime[i], 2 * k - 2 * s - 1) % mo *
                      (prime[i] - 1) % mo;
                yu = (yu % mo + mo) % mo;
            }
            h[i].push_back(yu);
        }
    }
    dfs(1, 1, 1);
    cout << ans << endl;
    return 0;
}

标签:right,frac,limits,cdot,sum,笔记,杜教,学习,left
From: https://www.cnblogs.com/clapp/p/17591549.html

相关文章

  • Java学习-4.数组
    一、数组类型数组是存储多个变量(元素)的东西(容器),这多个变量的数据类型要一致。定义一个数组类型的变量,使用数组类型“类型[]”,例如,int[]。和单个基本类型变量不同,数组变量初始化必须使用newint[5]表示创建一个可容纳5个int元素的数组。Java的数组有几个特点:数组所有元素......
  • markdown学习
    markdown学习标题+空格+标题名一级标题+空格+标题名二级标题+空格+标题名三级标题字体斜体加粗加粗斜体划线引用天天向上,好好学习分割线图片超链接百度列表第一第二第三第一第二第三表格姓名性别年龄王肖泽男12施芊伊女14......
  • markdown学习
    markdown学习标题+空格+标题名一级标题+空格+标题名二级标题+空格+标题名三级标题字体斜体加粗加粗斜体划线引用天天向上,好好学习分割线图片超链接百度列表第一第二第三abc表格姓名性别年龄王肖泽男12代码foriinran......
  • Markdown格式学习测试草稿
    Markdown学习标题:二级标题三级标题字体hello,world!hello,world!hello,world!***hello,world!***hello,world!hello,world!引用选择狂神说java,走向人身巅峰分割线图片超链接超链接测试列表ABCACB表格名字性别生日张三男1997.1.1......
  • python数据分析师入门-学习笔记(第九节 爬虫的核心流程)
    学习链接:Python数据分析师入门爬虫的核心流程明确目标汽车成交量汽车评论信息汽车提车分享信息搜寻哪些网站或APP有我们要的资源汽车之家懂车帝易车分析数据所在位置,加载方式直接加载的额外的网络请求数据获取使用代码驱动APP或浏览器自己分析请求......
  • 深度学习基础语法
    深度学习基础-李沐课程跟学数据操作+数据预处理定义一个1-11个数值的一维张量x=torch.arange(12)tensor([0,1,2,3,4,5,6,7,8,9,10,11])通过shape访问张量的形状和张量中元素的总数x.shape元素总数x.numel改变一个张量的形状,但是不改变......
  • python数据分析师入门-学习笔记(第八节 python爬虫的准备工作)
    学习链接:Python数据分析师入门python爬虫的准备工作一台电脑尽量windows电脑语言环境编程语言爬虫并不是python独有Python开发环境Anaconda了解爬虫的实现和原理用代码去控制终端用代码直接发送请求CS(客户端服务器)/BS(浏览器服务器)模型CS/BS浏览......
  • ZROI 学习笔记之数学相关
    都别催!!!等我有时间了例题和详细讲解都会补回来的!!!7.29数论基础你不会不知道吧首先,你要知道\[a\equivb\pmodp\]是什么意思。然后,\[\dfrac{a}{d}\equiv\dfrac{b}{d}\pmod\dfrac{p}{d}\]也是成立的。扩展欧几里得-ExGCD裴蜀定理:\(\foralla,b\in\mathbf{Z},\......
  • 408-数据结构算法题笔记
    常用基本操作1.定义整数无穷大#defineINT_MAX=0x7f7f7f7f;2.绝对值函数intabs_(intx){ if(x<0)return-x; returnx;}3.最大最小值函数(一般可以直接写吧)intmin(inta,intb){ if(a<b)returna; returnb;}说明时空间复杂度可以先设neg:代码规范1.函......
  • 基于Alexnet深度学习神经网络的人脸识别算法matlab仿真
    1.算法理论概述       人脸识别是计算机视觉领域中一个重要的研究方向,其目的是识别不同人的面部特征以实现自动身份识别。随着深度学习神经网络的发展,基于深度学习神经网络的人脸识别算法已经成为了当前最先进的人脸识别技术之一。本文将详细介绍基于AlexNet深度学习神经......