首页 > 其他分享 >杜教筛——亚线性处理数论函数求和

杜教筛——亚线性处理数论函数求和

时间:2024-02-29 19:00:31浏览次数:31  
标签:right limits 数论 sum sqrt 杜教 求和 mathcal left

问题引入

给定一个数论函数 \(f(x)\),求 \(\sum\limits_{i=1}^nf(i)\)。

对 \(n \le 10^7\) 甚至 \(n \le 10^8\) 都是好做的,\(\mathcal O(n)\) 解决即可,但如果 \(n < 2^{31}\) 呢?

这就需要亚线性时间复杂度的算法,杜教筛 就是其一。

杜教筛

杜教筛是一种能在幂时间 \(\mathcal O(n^\frac23)\) 下对数论函数进行求和的算法。

记 \(S(n) = \sum\limits_{i=1}^nf(i)\),所求即 \(S(n)\)。

考虑构造另一个函数 \(g(x)\),然后做狄利克雷卷积:

\[(f * g)(n) = \sum_{d|n}f(d)g\left(\dfrac nd\right) \]

那么有:

\[\sum_{i=1}^n(f * g)(i) = \sum_{d=1}^ng(d)\sum_{i=1}^{\lfloor\frac nd\rfloor}f(i) = \sum_{d=1}^ng(d)S\left(\lfloor\dfrac nd\rfloor\right) \]

把 \(g(1)S(n)\) 拿出来,就有:

\[g(1)S(n) = \sum_{i=1}^n(f*g)(i) - \sum_{i=2}^ng(d)S\left(\lfloor\dfrac nd\rfloor\right) \]

然后关于 \(\lfloor\dfrac nd\rfloor\) 数论分块就行。

所以 \(g(x)\) 需要满足以下性质:

  • \(\sum\limits_{i=1}^n(f*g)(i)\) 可以在亚线性时间复杂度内求得。
  • \(g(x)\) 的前缀和可以在亚线性时间复杂度内求得。

关于时间复杂度,将求 \(\sum\limits_{i=1}^n(f*g)(i)\) 和求 \(g(x)\) 的前缀和的时间复杂度都视作 \(\mathcal O(1)\) 的话,可以有:

\[T(n) = \mathcal O(\sqrt n) + \mathcal O\left(\sum_{i=2}^{\sqrt n} T(i) + T\left(\lfloor\dfrac ni\rfloor\right)\right) \]

展开,有:

\[T(n) = \mathcal O(\sqrt n) + \mathcal O\left(\sum_{i=2}^\sqrt n\mathcal O(\sqrt i) + \sum_{j=2}^\sqrt i T(j) + \mathcal O\left(\sqrt{\lfloor\dfrac ni\rfloor}\right) + \sum_{j=2}^\sqrt{\lfloor\frac ni\rfloor} T(j)\right) \]

因为 \(\lim\limits_{x \to \infin} \dfrac{n^\frac12}{n^\frac14} = \infin\),所以 \(\sum\limits_{j=1}^\sqrt i T(j)\) 和 \(\sum\limits_{j=1}^\sqrt{\lfloor\frac ni\rfloor} T(j)\) 可视作高阶无穷小,忽略不计;\(\sqrt i < \sqrt{\dfrac ni}\),忽略不计:

\[T(n) = \mathcal O(\sqrt n) + \mathcal O\left(\sum_{i=2}^\sqrt n \sqrt{\lfloor\frac ni\rfloor} \right) < \mathcal O\left(\int_0^\sqrt n\sqrt{\frac nx}\,\mathrm dx \right) = \mathcal O(n^\frac34) \]

积分步骤戳这里 O.o

考虑优化:前 \(B > n^{0.5}\) 个前缀和暴力求。时间复杂度为:

\[\mathcal O(B) + \mathcal O\left(\int_0^\frac nb \sqrt\frac nx \,\mathrm dx \right) = \mathcal O(B) + \mathcal O\left(\dfrac n{\sqrt B}\right) \]

积分步骤戳这里 o.O

根据均值不等式,当 \(B\) 取 \(n^\frac23\) 时,时间复杂度最小,为 \(\mathcal O(n^\frac23)\)。

实际实现中,因为递归部分常数较大,\(B\) 可以取大一些。例如 \(n < 2^{31}\) 时,可以取 \(B = 10^7\)。

模板

\(\mathcal{PORTAL}\)

分别求:

\[\sum_{i=1}^n \varphi(i) \\ \sum_{i=1}^n \mu(i) \]

\(1 \le n \le 2^{31}\)。

显然杜教筛,分别考虑 \(g\) 就好。

\(f = \varphi\)

注意到 欧拉函数的性质 中有一条是 \(\sum\limits_{d | n} \varphi(d) = n\),所以我们取 \(g = I\)(\(\forall x, I(x) = 1\)),就有 \((f * g)(n) = n\),\(g\) 的前缀和也显然。

\(f = \mu\)

注意到 莫比乌斯函数的性质 中有一条是 \(\sum\limits_{d|n}\mu(d) = \begin{cases}1 & n = 1 \\ 0 & \text{otherwise} \end{cases}\),所以我们同样取 \(g = I\),就有 \((f * g)(n) = \begin{cases}1 & n = 1 \\ 0 & \text{otherwise} \end{cases}\)。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

constexpr int N = 1e7 + 10;

int n, mu[N]; ll phi[N];
int prn, prime[N];
bool vis[N];

map<int, ll> S;

void init(int n) {
    phi[1] = mu[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) {
            phi[i] = i - 1, mu[i] = -1;
            prime[++prn] = i;
        }
        for (int j = 1; j <= prn && i * prime[j] <= n; j++) {
            vis[i * prime[j]] = 1;
            if (i % prime[j]) phi[i * prime[j]] = phi[i] * phi[prime[j]], mu[i * prime[j]] = -mu[i];
            else {phi[i * prime[j]] = phi[i] * prime[j]; break;}
        }
    }
    for (int i = 2; i <= n; i++) phi[i] += phi[i - 1], mu[i] += mu[i - 1];
}

ll Sphi(int n) {
    if (n <= 1e7) return phi[n];
    if (S.find(n) != S.end()) return S[n];
    ll res = (n + 1ll) * n / 2;
    for (uint l = 2, r; l <= n; l = r + 1) r = n / (n / l), res -= (r - l + 1) * Sphi(n / l);
    return S[n] = res;
}

int Smu(int n) {
    if (n <= 1e7) return mu[n];
    if (S.find(n) != S.end()) return S[n];
    int res = 1;
    for (uint l = 2, r; l <= n; l = r + 1) r = n / (n / l), res -= (r - l + 1) * Smu(n / l);
    return S[n] = res;
}

void solve() {
    cin >> n; 
    S.clear();
    cout << Sphi(n) << ' ';
    S.clear();
    cout << Smu(n) << '\n';
}

int main() {
    ios::sync_with_stdio(0); cin.tie(nullptr), cout.tie(nullptr);
    init(1e7); int t; cin >> t;
    while (t--) solve();
    return 0;
}

标签:right,limits,数论,sum,sqrt,杜教,求和,mathcal,left
From: https://www.cnblogs.com/chy12321/p/18045153

相关文章

  • 学习之请求和响应
    3.2请求和响应报文3.2.1报文的格式主体上分为报文首部和报文主体,中间空行隔开报文部首可以继续细分为"行"和"头"3.2.2请求报文客户端发给服务端的报文请求报文格式请求首行(请求行);GET/POST资源路径?参数HTTP/1.1(默认是通过GET请求获取服务器信......
  • 花神的数论题(数位dp)
    花神的数论题题目描述设\(\text{sum}(i)\)表示\(i\)的二进制表示中\(1\)的个数。给出一个正整数\(N\),花神要问你\(\prod_{i=1}^{N}\text{sum}(i)\),也就是\(\text{sum}(1)\sim\text{sum}(N)\)的乘积。数据范围\(1\leN\le10^{15}\)。解法首先我们要......
  • 假期vue学习笔记14 求和案例vue版本
     <template>  <div>    <h1>当前求和为:{{sum}}</h1>    <selectv-model.number="n">      <optionvalue="1">1</option>      <optionvalue="2">2</option>......
  • 假期vue学习笔记15 求和mapstate_mapgetter
     importVuefrom'vue'importAppfrom'./App.vue'importstorefrom'./store'Vue.config.productionTip=falsenewVue({  el:'#root',  render:h=>h(App),  store,  beforeCreate(){    Vue.......
  • 基础数论学习笔记
    1.辗转相减利用辗转相减法求最大公约数,即\(gcd(a,b)\)。假设\(a>b\),则gcd(a,b)=gcd(a−b,b),不断的利用大的数减去小的数,就能得到最大公约数。1.证:若\(n,m(n>m)\)互质,则$(n-m),m$互质若不互质,则设\(n-m=k*a,m=k*b\)\(\thereforen-k*b=k*a......
  • Toyota Programming Contest 2024#2(AtCoder Beginner Contest 341)D - Only one of two
    目录链接题面题意题解代码总结链接D-Onlyoneoftwo题面题意求第\(k\)个只能被\(N\)或\(M\)整除的数题解\([1,x]\)中的能被\(n\)整除的数有\(\lfloor\frac{x}{n}\rfloor\)个\([1,x]\)中的能被\(m\)整除的数有\(\lfloor\frac{x}{m}\rfloor\)个\([1,x]\)中的能被\(n\)......
  • 杜教筛学习笔记
    杜教筛是求一个数论函数f的前缀和,令其为S我们考虑构造一个数论函数g,根据狄利克雷卷积\[\begin{aligned}\sum_{i=1}^{n}(f*g)(i)&=\sum_{i=1}^{n}\sum_{d\midi}g(d)f\left(\frac{i}{d}\right)\\&=\sum_{i=1}^{n}g(i)S\le......
  • 数论函数
    数论函数常见数论函数\(\epsilon(n)=[n=1]\)\(I(n)=1...\)\(id(n)=n\)\(id^k(n)=n^k\)\(\mu\)莫比乌斯函数\(\phi\)欧拉函数\(\tau\)约数个数\(\sigma\)约数和欧拉函数\(\phi(n)\)表示的是小于等于n和n互质的数的个数,是积性函数\(\phi(p^k)=p^k-p^{k-1}\)\(n=\sum_......
  • 数论分块性质优化DP状态
    6311.mobitel给定一个r行s列的矩阵,每个格子里都有一个正整数。问如果从左上角走到右下角,且每次只能向右或向下走到相邻格子,那么使得路径上所有数的乘积不小于n的路径有多少条?对于100%的数据,1<=r,s<=300,1<=n<=10^6,矩阵中的数不超过10^6。so,一个普通的思想就是设f[......
  • 【学习笔记】关于数论与平面几何的一切
    快速幂人话求\(a\)的\(n\)次方,其实就是根据二进制唯一分解定理给\(a^n\)拆成\(\log{n}\)个\(a^{2^i}\),递推求出从\(a^0\)到\(a^{2^i}\)每个数,如果\(n\)的二进制第\(i\)位为1,则将答案乘上\(a^{2^i}\)llQpow(lla,llb){//一开始a就是a的一次方llans=1;while(b......