Min25 筛法
之前学习的的确是太浅薄了,于是重新学习一下。
- 可以做什么?
对于满足条件的积性函数 ,求其前 项和 。
- 需要准备些什么?
设 ,即为所有整除的不同点值。
设 代表 的所有质数。
设 为 的最小质因子。
第一部分#
我们需要对于 ,求出 。
这里要求:,即可以表示成一个关于 的低次多项式,那么我们把多项式拆成若干个单项式分别求和即可,记为 。
设 为用 做完线性筛后剩下的数的 之和,也就是 。
我们让 从 依次增大,这样枚举完 的质数后就是要求的了。
就是一个自然数幂和,不多赘述,现在我们看怎么从 推到 。
相比于 , 筛掉了所有 的 ,我们从 中提出一个 ,然后一定有 ,这个东西就是 去掉前边质数的贡献,因此我们有:
其中 是前 个质数的贡献。
这样就完成了递推。
第二部分#
设 为 ,我们要求出 。
的贡献分成质数和合数两部分,质数就是 。
对于合数,我们枚举最小质因子 及其次数 ,显然这里 。
那么贡献就是
直接递归即可。
两者的复杂度都可以证明是 ,实际上比杜教筛还要快。
拓展#
我们能不能对于 ,求出 呢?
我们知道杜教筛可以记忆化,但是这里即使记忆化复杂度依旧爆炸,我们考虑把递归改成递推的。
首先改一下 的定义:我们只考虑合数的贡献不考虑质数,这样做的好处是我们定义域满足 。
那么式子就是:
显然和递归是一个复杂度的,那么我们就保持复杂度不变的同时完成了递推所有值。
下面是一个 的代码, 是 的质因子个数。
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现