学习笔记——莫比乌斯反演
前言#
时隔一年,学了点多项式基础,然后来搞搞数论。学一下颓柿子。
数论分块#
是用莫反解决问题的基础。
形式:如果有式子 需要求值,我们能在 的复杂度内求出上面这个式子的值。即需要求的东西中需要有带整除的值,所以也叫整除分块。
考虑到当 很大的时候,我们这个 的取值是非常少的。可以证明取值不超过 个。
若 ,那么就算每个 都有一个不同的 ,那总数也不超过 个。
若 ,那么有 ,所以也不超过 个。
综上,这样的取值不超过 个。
接下来我们需要一个性质:。
证明略。
然后就有如下结论:对于每个 相等的块,其左端点为 的话,右端点就是 。
令 ,有 。
则 。所以最大的 就是 。
这样一来,代码就很好写了。
void solve(){
ll n;cin>>n;
ll ans=0;
for(ll l=1,r;l<=n;l=r+1){
r=n/(n/l);ans+=(r-l+1)*(n/l);
}cout<<ans<<'\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;for(cin>>T;T--;)solve();
return 0;
}
int main()
{
ll n,k,ans;
scanf("%lld%lld",&n,&k);ans=n*k;
for(ll l=1,r;l<=n;l=r+1){
if(k/l) r=min(k/(k/l),n);else r=n;
ans-=(l+r)*(r-l+1)/2*(k/l);
}printf("%lld\n",ans);
}
以及一个显然的结论:
前置知识#
你需要会素数筛(好歹是线性筛吧),然后唯一分解定理。
然后是调和级数求和是 也得知道。
数论函数#
定义:若对于 ,有 ,则 为积性函数。
单位函数#
任何函数卷积上这个函数都是那个函数本身。单位函数是积性的。
除数函数#
为 的约数个数, 为约数和,简称 。除数函数也是积性的。
欧拉函数#
内容比较多,主要是关于欧拉定理和欧拉筛的, 表示小于 的与 互质的数的个数。
其中 表示 的第 个质因子。当然也可以用欧拉筛出欧拉函数。
幂函数#
狄利克雷卷积#
一种特殊的因数卷积。
是 和 的狄利克雷卷积,记做 。
性质:满足结合律,并且如果 都是积性函数,那么 也是积性函数。
一些常见的卷积:。
也就是:
莫比乌斯函数#
这东西由于也是积性的,可以用线性筛求。
莫比乌斯反演#
,则 是 的莫比乌斯变换。
那么 就是 的莫比乌斯逆变换。
莫比乌斯反演定理指出:。
一些例题#
题单中指出了莫比乌斯反演的三种形式,也就是最常见的三种。
Case1:
然后你整除分块搞一下就可以 求了。
Case2:
然后和上面那个同理,最后
Case3:
接着令 ,则有:
P2568 GCD#
本题要求:
然后暴力枚举直接做就好了。
const int MAXN=1e7+10;
int mu[MAXN],pr[MAXN],p[MAXN],cnt,n;
void init(){
p[1]=1;mu[1]=1;
rep(i,2,n){
if(!p[i]) pr[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*pr[j]<=n;j++){
p[i*pr[j]]=1;
if(i%pr[j]){
mu[i*pr[j]]=-mu[i];
}else{mu[i*pr[j]]=0;break;}
}
}
}
int pre[MAXN];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;init();
rep(i,1,n) pre[i]=pre[i-1]+mu[i];
int ans=0;
rep(i,1,cnt){
int m=n/pr[i],cur=0;
for(int l=1,r;l<=m;l=r+1){
r=m/(m/l);cur+=(pre[r]-pre[l-1])*(m/l)*(m/l);
}ans+=cur;
}cout<<ans<<'\n';
return 0;
}
P1891 疯狂 LCM#
题目要求:
令 ,这是个积性函数,可以筛出来。
const int MAXN=1e6+10;
int p[MAXN],pr[MAXN],cnt;
ll f[MAXN];
void init(){
f[1]=1;p[1]=1;
rep(i,2,MAXN-10){
if(!p[i]){pr[++cnt]=i,f[i]=1ll*i*(i-1)+1;}
for(int j=1;j<=cnt&&i*pr[j]<=MAXN-10;j++){
p[i*pr[j]]=1;
if(i%pr[j]) f[i*pr[j]]=f[i]*f[pr[j]];
else{f[i*pr[j]]=f[i]+(f[i]-f[i/pr[j]])*pr[j]*pr[j];break;}
}
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
init();
int T;for(cin>>T;T--;){
int n;cin>>n;
cout<<1ll*(n*f[n]+n)/2<<'\n';
}
return 0;
}
SP21615 NAJPWG - Playing with GCD#
题目要求:
直接预处理就好了。
const int MAXN=1e5+10;
int p[MAXN],pr[MAXN],phi[MAXN],cnt;
int ans[MAXN];
void init(){
phi[1]=1;p[1]=1;
rep(i,2,MAXN-10){
if(!p[i]) pr[++cnt]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&i*pr[j]<=MAXN-10;j++){
p[i*pr[j]]=1;
if(i%pr[j]) phi[i*pr[j]]=phi[i]*phi[pr[j]];
else{phi[i*pr[j]]=phi[i]*pr[j];break;}
}
}rep(i,1,MAXN-10) ans[i]=ans[i-1]+i-phi[i];
}
void solve(int Cas){
int n;
cin>>n;
cout<<"Case "<<Cas<<": "<<ans[n]<<'\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
init();
int T;cin>>T;
rep(_,1,T) solve(_);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通