首页 > 其他分享 >Min25 筛法

Min25 筛法

时间:2024-06-12 20:14:59浏览次数:21  
标签:prime lfloor frac 筛法 int Min25 质数 sum

之前学习的的确是太浅薄了,于是重新学习一下。

  • 可以做什么?

对于满足条件的积性函数 \(f(n)\),求其前 \(n\) 项和 \(\sum_{i=1}^nf(i)\)。

  • 需要准备些什么?

设 \(N=\{x|x=\lfloor\frac{n}{i}\rfloor\}\),即为所有整除的不同点值。

设 \(B=\sqrt n,p_{k}\) 代表 \(\le B\) 的所有质数。

设 \(mn(n)\) 为 \(n\) 的最小质因子。

第一部分

我们需要对于 \(i\in N\),求出 \(\sum_{p_k\leq i}f(p_k)\)。

这里要求:\(f(p_k)=\sum_{j=0}c_j(p_k)^j\),即可以表示成一个关于 \(p_k\) 的低次多项式,那么我们把多项式拆成若干个单项式分别求和即可,记为 \(g(n)\)。

设 \(G_k(n)\) 为用 \(p_{1}\to p_{k}\) 做完线性筛后剩下的数的 \(g(i)\) 之和,也就是 \(G_k(n)=\sum_{j=1}^k g(p_j)+\sum_{i=p_k+1}^n[mn(i)>p_k]g(i)\)。

我们让 \(k\) 从 \(0\) 依次增大,这样枚举完 \(\leq B\) 的质数后就是要求的了。

\(G_0(n)\) 就是一个自然数幂和,不多赘述,现在我们看怎么从 \(G_{k-1}\) 推到 \(G_k\)。

相比于 \(G_{k-1}(n)\),\(G_k(n)\) 筛掉了所有 \(mn(i)=p_k\) 的 \(i\),我们从 \(i\) 中提出一个 \(p_k\),然后一定有 \(mn(\frac{i}{p})> p_{k-1}\),这个东西就是 \(G_{k-1}(n)\) 去掉前边质数的贡献,因此我们有:

\[G_k(n)=G_{k-1}(n)-g(n)(G_{k-1}(\lfloor \frac{n}{p_k}\rfloor )-sum_{k-1})) \]

其中 \(sum_k\) 是前 \(k\) 个质数的贡献。

这样就完成了递推。

第二部分

设 \(S_k(n)\) 为 \(\sum_{i=1}^n[mn(i)>p_k]f(i)\),我们要求出 \(S_0(n)\)。

\(S_k(n)\) 的贡献分成质数和合数两部分,质数就是 \(G_0(n)-sum_{k}\)。

对于合数,我们枚举最小质因子 \(p_{j}(j>k)\) 及其次数 \(c\),显然这里 \(p_j\leq B\)。

那么贡献就是

\[S_k(n)=G_0(n)-sum_k+\sum_{j>k}\sum_cf(p_j^c)(S_{j,\lfloor\frac{n}{p_j^c}\rfloor}+[c\neq 1]) \]

直接递归即可。

两者的复杂度都可以证明是 \(O(\frac{n^{\frac{3}{4}}}{\ln\ln n})\),实际上比杜教筛还要快。

拓展

我们能不能对于 \(i\in N\),求出 \(S_k(i)\) 呢?

我们知道杜教筛可以记忆化,但是这里即使记忆化复杂度依旧爆炸,我们考虑把递归改成递推的。

首先改一下 \(S_k(n)\) 的定义:我们只考虑合数的贡献不考虑质数,这样做的好处是我们定义域满足 \(p_k^2\leq n\) 。

那么式子就是:

\[S_k(n)=\sum_{j>k}\sum_cf(p_j^c)(S_{j,\lfloor\frac{n}{p_j^c}\rfloor}+G_0(\lfloor\frac{n}{p_j^c}\rfloor)-sum_j+[c\neq 1]) \]

\[S_k(n)=S_{k+1}(n)+\sum_cf(p_{k+1}^c)(S_{k+1,\lfloor\frac{n}{p_{k+1}^c}\rfloor}+G_0(\lfloor\frac{n}{p_{k+1}^c}\rfloor)-sum_{k+1}+[c\neq 1]) \]

显然和递归是一个复杂度的,那么我们就保持复杂度不变的同时完成了递推所有值。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
template <typename T>inline void read(T &x)
{
    x=0;char c=getchar();bool f=0;
    for(;c<'0'||c>'9';c=getchar())f|=(c=='-');
    for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+(c-'0');
    x=(f?-x:x);
}
const int N = 1e6+7;
#define int long long
typedef long long LL;
int sum[N];
namespace sub
{
    int v[N],g[N],prime[N],tot=0;
    int solve(int n)
    {
        g[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(!v[i])
            {
                v[i]=i;
                prime[++tot]=i;
                g[i]=2;
            }
            for(int j=1;j<=tot;j++)
            {
                if(prime[j]>v[i]||1ll*i*prime[j]>n)break;
                int k=i*prime[j];
                v[k]=prime[j];
                if(i%prime[j]==0)
                {
                    g[i*prime[j]]=g[i];
                    break;
                }
                g[i*prime[j]]=g[i]*2;
            }
        }
        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+g[i];
    }
}
int v[N],g[N];
int prime[N],tot=0;
int sg[N],R;
void init(int n)
{
    g[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!v[i])
        {
            v[i]=i;
            prime[++tot]=i;
            g[i]=2;
            sg[tot]=sg[tot-1]+g[i];
        }
        for(int j=1;j<=tot;j++)
        {
            if(prime[j]>v[i]||1ll*i*prime[j]>n)break;
            int k=i*prime[j];
            v[k]=prime[j];
            if(i%prime[j]==0)
            {
                g[i*prime[j]]=g[i];
                break;
            }
            g[i*prime[j]]=g[i]*2;

        }
    }
}
int num[N],cnt=0,G[N],id1[N],id2[N],B;
int F[N],S[N];
void init()
{
    for(int j=tot;j>=0;j--)
    {
        for(int u=1;u<=cnt&&prime[j]*prime[j]<=num[u];u++)
        {
            int x=num[u];
            F[u]=S[u];
        }
        if(j==0)break;
        for(int u=1;u<=cnt&&prime[j]*prime[j]<=num[u];u++)
        {
            int x=num[u];
            int c=1,cur=prime[j];
            for(;cur<=x;cur=cur*prime[j],c++)
            {
                int v=(x/cur<=B?id1[x/cur]:id2[R/(x/cur)]);
                int w=(x/cur>prime[j]?F[v]+G[v]-sg[j]:0);
                S[u]=S[u]+2*(w+(c!=1));
            }
        }
    }
}
signed main()
{
    freopen("a.in","r",stdin);
    //freopen("count.out","w",stdout);
    int n;
    read(n);R=n;
    B=sqrt(n);
    init(B);
    for(int l=1,r;l<=n;l=r+1)
    {
        r=(n/(n/l));
        num[++cnt]=(n/l);
        G[cnt]=(n/l)-1;
        if(n/l<=B)id1[n/l]=cnt;
        else id2[n/(n/l)]=cnt;
    }
    for(int j=1;j<=tot;j++)
    for(int i=1;i<=cnt&&1ll*prime[j]*prime[j]<=num[i];i++)
    {
        int x=num[i]/prime[j];
        if(x<=B)x=id1[x];
        else x=id2[n/x];
        G[i]-=(G[x]-(j-1));
    }
    for(int i=1;i<=cnt;i++)G[i]=G[i]*2;
    init();
    cout<<F[1]+G[1]+1;
    return 0;
}


标签:prime,lfloor,frac,筛法,int,Min25,质数,sum
From: https://www.cnblogs.com/jesoyizexry/p/18244573

相关文章

  • 取素数优化——埃拉托斯特尼筛法(Sieve of Eratosthenes)
    埃拉托斯特尼筛法(SieveofEratosthenes)是一种用来生成一定范围内所有素数的算法。其基本思想是从小到大遍历每个数,如果当前数是素数,则将其所有的倍数标记为非素数。这个过程中,所有未被标记为非素数的数即为素数。下面是使用埃拉托斯特尼筛法来计算区间[x,y]内的素数个数的修......
  • 算法课程笔记——素数朴素判定&埃氏筛法
    算法课程笔记——素数朴素判定&埃氏筛法sqrt返回浮点数,而且这样可防溢出优化i*i会更快......
  • 筛法学习笔记
    埃氏筛枚举质数\(p_i\),每次去除所有是\(p_i\)倍数的数,总效率大概是\(O(n\log\logn)\)。int_prm=0,prm[M];boolisprm[M];voidGet_phi(intn){ for(inti=2;i<=n;i++){ if(isprm[i])continue; prm[++_prm]=i; for(intj=i*i;j<=n;j+=i)isprm[j]=1; }}值......
  • 《算法笔记》系列----质数的判断(埃氏筛法)
    目录一、朴素算法二、埃氏筛法1、与朴素算法对比2、算法介绍   3、例题即代码实现一、朴素算法 从素数的定义中可以知道,一个整数n要被判断为素数,需要判断n是否能被2.3.n-1中的一个整除。只2,3..n-1都不能整除n,n才能判定为素数,而只要有一个能整除n的数出现,n就......
  • C++实现欧拉筛法
    Euler筛法介绍以筛出100以内(含100)的所有素数为例来说明一下欧拉筛法的原理。和Eratosthenes筛法一样,Euler筛法也从2开始筛,但Eratosthenes筛法会把2的倍数一批全部筛掉,而Euler筛法用2筛时仅仅把2*2(即4)筛掉,而把其它偶数留到后面再筛掉,从而避免了一个偶数被多次筛除带来的性能开销,......
  • 浅谈筛法
    浅谈筛法Euler筛Eratosthenes筛可以证明(不是“不难证明”),Eratosthenes筛的复杂度为\(\Theta(n\log\logn)\)。Eratosthenes筛的复杂度证明Dirichlet前缀和以P5495【模板】Dirichlet前缀和为例。给定\(a_1,a_2,\cdots,a_n\),求\(b_1,b_2,\cdots,b_n\),满足\[b_i......
  • 筛法思想的题目
    这道题目比较经典,或者说这种思想比较经典。这种筛法的思想。我们正着想对于每一个\(n、n-1、n-2、...、2、1\)都分解一遍质因数显然是来不及的时间复杂度达到\(O(n\sqrt{n})\)我们考虑对于每一个1e6以内的质因数的个数跑了一下程序是\(78498\)个素数定理告诉我们不超过x......
  • 质数基础筛法
    目录埃氏筛线性筛埃氏筛埃氏筛是一种筛素数的方法,埃氏筛的思想很重要,主要是时间复杂度朴素的埃氏筛的时间复杂度是\(O(nlogn)\)这个复杂度是调和级数vector<int>p;intvis[N];voidsolve(){ rep(i,2,n){ if(!vis[i]) p.pb(i); for(intj=i+i;j<=n;j+=i) vis[j]=1; ......
  • 根据筛法规则对整数分类,建立树状结构
    筛法目前一般用来找整数序列中的素数,不是素数的元素被丢掉了。如果仅把筛法当成一种分类规则,把筛掉的元素和留下的元素算作不同的分类,并用每一类中的最小元素递归地执行筛法,那么能把所有正整数保留下来,并建立一个树状结构。例如,初始集合是正整数集,根据模最小元素p是否为0,可把所有......
  • O(n)筛法
    voidpre(){ vis[1]=g[1]=f[1]=mu[1]=phi[1]=d[1]=1; for(inti=2;i<=n;i++){ if(!vis[i]){ pri[++tot]=i;//质数 phi[i]=i-1;//欧拉函数 mu[i]=-1;//莫比乌斯 d[i]=2;//约数个数 num[i]=1;//最小质因子个数 f[i]=i+1;//约数和 g[i]=i+1;//最小质......