首页 > 其他分享 >杜教筛

杜教筛

时间:2023-01-28 19:44:13浏览次数:57  
标签:lfloor frac 前缀 int sum rfloor 杜教

杜教筛

设现在要求积性函数 \(f\) 的前缀和, 设 \(\sum_{i=1}^{n}f(i)=S(n)\)
找一个积性函数\(g\),考虑它们的狄利克雷卷积的前缀和

\[\sum_{i=1}^{n} (f*g)(i)=\sum_{i=1}^{n}\sum_{d|i}f(d)g(\frac{i}{d}) \]

先枚举 \(d\) 提出 \(g\)

\[\sum_{i=1}^{n} (f*g)(i)= \sum_{d=1}^{n}g(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}f(i) \]

把\(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\)替换为\(S(\lfloor\frac{n}{d}\rfloor)\)

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

可以发现从\(1\)开始的前缀和减去从\(2\)开始的前缀和就是第一项,即

\[g(1)S(n)=\sum_{i=1}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) \]

所以得到杜教筛的核心式子:

\[g(1)S(n)=\sum_{i=1}^{n}(f*g)(i)-\sum_{i=2}^{n}g(i)S(\lfloor\frac{n}{i}\rfloor) \]

则如果可以找到一个合适的积性函数\(g\),使得可以快速算出\(\sum_{i=1}^{n}(f*g)(i)\)和\(g\)的前缀和,便可以用数论分块递归地求解

代码框架如下

il int GetSum_f(cs int n){ // 算 f 前缀和的函数
    ri int as=sum_f_g(n); // sum_f_g(n)是算 f * g 的前缀和
    // 数论分块
    for(ri int l=2,r=0;l<=n;l=r+1){ // 注意从 2 开始
        r=(n/(n/l)); // g_sum 是 g 的前缀和,递归求解
        as-=(sum_g(r)-sum_g(l-1))*GetSum_f(n/l);
    }
    return as;
}

复杂度\(O(n^{\frac{3}{4}})\)

还可以进一步优化,即先线性筛出前 \(m\) 个答案,之后再用杜教筛,复杂度是\(O(\frac{n}{\sqrt{n}})\)
当\(m=n^{\frac{2}{3}}\)时,复杂度为\(O(n^\frac{2}{3})\)

可以使用哈希表来存下已经求过的答案,第一篇题解说可以不用。

考虑到上面的求和过程中出现的都是 \(\lfloor\frac{n}{i}\rfloor\)。开一个大小为两倍 \(\sqrt{n}\) 的数组 \(f\) 记录答案。如果现在需要求出 GetSum_f(x) ,若 \(x\le\sqrt{n}\),返回 \(f[x]\) ,否则返回 \(f[sqrt(n)+n/i]\) 即可。

code

求\(\sum_{i=1}^n\varphi(i)\),\(\sum_{i=1}^n\mu(i)\)
题目链接
题解

AC·code
#include<bits/stdc++.h>
#define il inline
#define cs const
#define ri register
#define ll long long
using namespace std;
namespace Q{
    il int rd(){
        ri int x=0,f=1;ri char c=getchar();
        while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0'&&c<='9') x=x*10+(c^48),c=getchar();
        return x*f;
    }
    il void wt(int x){
        if(x<0) x=-x,putchar('-');
        if(x>=10) wt(x/10);
        return putchar(x%10+48),void();
    }
    il void wl(ll x){
        if(x<0) x=-x,putchar('-');
        if(x>=10) wl(x/10);
        return putchar(x%10+48),void();
    }
} 
namespace djs{
    cs int N=5e6;
    int ss[N],mu[N+5],cnt;
    ll fi[N+5];
    il void init(){
        mu[1]=fi[1]=1;
        for(ri int i=2;i<=N;++i){
            if(!fi[i]) ss[++cnt]=i,fi[i]=i-1,mu[i]=-1;
            for(ri int j=1;j<=cnt&&1ll*ss[j]*i<=N;++j){
                if(i%ss[j]){
                    fi[i*ss[j]]=fi[i]*fi[ss[j]];
                    mu[i*ss[j]]=-mu[i];
                }
                else{
                    fi[i*ss[j]]=fi[i]*ss[j];
                    break;
                }
            }
        }
        for(ri int i=2;i<=N;++i){
            fi[i]+=fi[i-1],mu[i]+=mu[i-1];
        }
        return;
    }
    unordered_map<int,int> Mu;
    unordered_map<int,ll> Fi;
    il ll varphi(int n){
        if(n<=N) return fi[n];
        else if(Fi.count(n)) return Fi[n];
        ri ll phi=(1ll+n)*n/2;
        for(ri unsigned int l=2,r=0;l<=n;l=r+1){
            r=n/(n/l),phi-=1ll*(r-l+1)*varphi(n/l);
        }
        return Fi[n]=phi;
    }
    il int get_mu(int n){
        if(n<=N) return mu[n];
        else if(Mu.count(n)) return Mu[n];
        ri int smu=1;
        for(ri unsigned int l=2,r=0;l<=n;l=r+1){
            r=n/(n/l),smu-=(r-l+1)*get_mu(n/l);
        }
        return Mu[n]=smu;
    }

} using namespace djs;

signed main(){
    init();
    for(ri int i=Q::rd(),n;i;--i){
        n=Q::rd();
        Q::wl(varphi(n)),putchar(' ');
        Q::wt(get_mu(n)),putchar('\n');
    }
    return 0;
}

标签:lfloor,frac,前缀,int,sum,rfloor,杜教
From: https://www.cnblogs.com/windymoon/p/17071163.html

相关文章

  • 杜教筛学习笔记
    杜教筛是拿来求积性函数前缀和的东西\(h=f*g\)\(s(n)=\sum\limits_{i=1}^ng(i)\)而杜教筛可以在\(O(n^{\frac23})\)的复杂度内求出\(s(n)\),前提是存在两个很好求前......
  • HDU 6439 2018CCPC网络赛 Congruence equationI(杜教筛 + 莫比乌斯反演 + 伯努利数)
      大致题意:给你一个长度为k的序列a。对于序列c,当  时,;当时,取[0,m)中任意一个数字。令  表示满足  的序列c的方案数。现在让你求 。          ......
  • 【学习小记】狄利克雷卷积+杜教筛
    Preface这东西分明就是玄学暴力用来求简单的数论函数的前缀和,像φ,μ这类的东西当然,约数和,约数个数之类的也是可以的Text数论函数是指定义域是整数,陪域是复数的函数Dirich......
  • 【学习小记】狄利克雷卷积+杜教筛
    Preface这东西分明就是玄学暴力用来求简单的数论函数的前缀和,像φ,μ这类的东西当然,约数和,约数个数之类的也是可以的Text数论函数是指定义域是整数,陪域是复数的函数Dirich......
  • 杜教筛
    接卷积杜教筛为了改模拟考试题被迫学的参考这篇blog设有积性函数\(f(x)\),求$\sum\limits_{i=1}^n{f(x)}$。当数据范围太大(如[1,1e9])时无法直接计算,要考......
  • 【XSY4350】摆(行列式,数论,杜教筛)
    题面摆题解首先我们将原矩阵写成\(A+B\),其中\(B\)全是\(C\),那么\(A\)的第\(i\)行就只有其倍数处有值,且\(A_{i,i}=1-C,A_{i,j(i|j\landi\neqj)}=-C\)。那么......
  • P4213 【模板】杜教筛(Sum)
    题目链接P4213【模板】杜教筛(Sum)题目描述给定一个正整数,求\[ans_1=\sum_{i=1}^n\varphi(i)\]\[ans_2=\sum_{i=1}^n\mu(i)\]输入格式本题单测试点内有多组数据。......
  • 【51NOD1847】奇怪的数学题(杜教筛,min_25筛,第二类斯特林数解决自然数幂求和)
    设\(f(n)\)表示\(n\)的次大因数。\[\begin{aligned}&\sum_{i=1}^n\sum_{j=1}^nf(\gcd(i,j))^k\\=&\sum_{d=1}^nf(d)^k\sum_{i=1}^{(n/d)}\sum_{j=1}^{(n/d)}[\gcd(i......
  • BZOJ 4805(欧拉函数求和-杜教筛)
    Description给出一个数字N,求sigma(phi(i)),1<=i<=NInput正整数N。N<=2*10^9Output输出答案。SampleInput10SampleOutput32HINT杜教筛入门#include<bits/stdc++......
  • 杜教筛
    没时间了,记几个公式好了。令\(S(n)=\sum_{i=1}^nf(i)\),则\(g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=\bm2}^nS(\lfloor\fracni\rfloor)\)。e.g.\(f=\mu,S(n)=\sum_{i......