<学习笔记> 莫比乌斯反演
但是手摸发现不仅可以从
性质一: 对于任意的正整数
证明
当
当
性质二:
证明
易证。莫比乌斯反演的证明#
形式一#
证明一
将上式换成以
根据性质一,只有
综上
证明二
设
单位元
根据狄利克雷卷积得到几个性质:
给出的条件等价于
根据性质一
变形#
证明
另
根据性质一有,只有当
莫比乌斯反演的性质#
莫比乌斯反演的应用#
P4449 于神之怒加强版 #
设
发现
那么
另
那么我们只需要线性求出
另
首先可以知道
那么我们尝试证明
我们设
因为有
那么就有
只有
那么
那么我们就可以在线性筛的时候求出,然后计算答案直接整数分块,复杂度
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5*1e6+10;
const int mod=1e9+7;
int prime[N],nprime[N],mul[N],f[N],sumf[N];
int T,k;
int qpow(int x,int p){
int ans=1;
while(p){
if(p&1) ans=(ans*x)%mod;
x=(x*x)%mod;
p>>=1;
}
return ans;
}
void get_prime(){
mul[1]=1;
f[1]=1;
for(int i=2;i<=N-10;i++){
if(!nprime[i]){
f[i]=(qpow(i,k)-1+mod)%mod;
prime[++prime[0]]=i;
mul[i]=-1;
}
for(int j=1;j<=prime[0] && i*prime[j]<=N-10;j++){
int tmp=i*prime[j];
nprime[tmp]=1;
mul[tmp]=mul[i]*mul[prime[j]];
if(i%prime[j]==0){
f[tmp]=f[i]*qpow(prime[j],k)%mod;
mul[tmp]=0;
break;
}
f[tmp]=(f[i]*f[prime[j]]%mod)%mod;
}
}
for(int i=1;i<=N-10;i++) sumf[i]=(sumf[i-1]+f[i])%mod;
}
signed main(){
scanf("%lld%lld",&T,&k);
get_prime();
while(T--){
int n,m;
scanf("%lld%lld",&n,&m);
if(n>m) swap(n,m);
int l=1,r=0;
int ans=0;
while(l<=n){
int ta=n/l,tb=m/l;
if(!ta||!tb) break;
r=min(n/ta,m/tb);
ans=(ans+ta*tb%mod*(sumf[r]-sumf[l-1]+mod)%mod)%mod;
l=r+1;
}
printf("%lld\n",ans);
}
}
DZY Loves Math #
首先它让求
然后套路的转化为
另
现在只需要求出
我们设
我们设
我们考虑
当
时
- 若最大值为
,那么只要满足一个为 ,所以有 (补一位进行二项式定理)
- 若最大值为
,就有
那么这部分答案为
当
时
这时不论
可以用线性筛来求,发现每个数会被最小的质数筛掉,那么我们维护一个
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e7+10;
int g[N],mnsum[N],excp[N];
int prime[N];
bool nprime[N];
void get_prime(){
for(int i=2;i<=N-5;i++){
if(!nprime[i]){
prime[++prime[0]]=i;
g[i]=mnsum[i]=excp[i]=1;
}
for(int j=1;j<=prime[0] && i*prime[j]<=N-5;j++){
int k=prime[j]*i;
nprime[k]=1;
if(i%prime[j]==0){
excp[k]=excp[i];
mnsum[k]=mnsum[i]+1;
if(excp[k]==1) g[k]=1;
else g[k]=(mnsum[excp[k]]==mnsum[k]?-g[excp[k]]:0);
break;
}
excp[k]=i,mnsum[k]=1;
g[k]=(mnsum[i]==1?-g[i]:0);
}
}
for(int i=1;i<=N-5;i++) g[i]+=g[i-1];
}
signed main(){
get_prime();
int T;
scanf("%lld",&T);
while(T--){
int a,b;
scanf("%lld%lld",&a,&b);
if(a>b) swap(a,b);
int l=1,r=0;
int ans=0;
while(l<=a){
int ta=a/l,tb=b/l;
if(!ta || !tb) break;
int r=min(a/ta,b/tb);
ans+=ta*tb*(g[r]-g[l-1]);
l=r+1;
}
printf("%lld\n",ans);
}
}
[SDOI2015]约数个数和#
首先给出结论
证明
设
设
设
要想
-
当
时,那么 可以取 。 -
当
时,那么 可以取 。
那么对于第一个质因子,符合条件的组合就有
以此类推,那么所有符合条件的组合就有
因此
回归正题那么原式就为
设
设
因为
根据莫比乌斯反演,就有
因为我们只需要求 $f(1),那么答案就是
整除分块就可以了。
code
// P3327 [SDOI2015] 约数个数和
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=50005;
int mul[N],suml[N];
int prime[N];
bool nprime[N];
void get_prime(){
mul[1]=1;
for(int i=2;i<=N-3;i++){
if(!nprime[i]){
prime[++prime[0]]=i;
mul[i]=-1;
}
for(int j=1;j<=prime[0] && i*prime[j]<=N-3;j++){
int k=prime[j]*i;
nprime[k]=1;
if(i%prime[j]==0){
mul[k]=0;
break;
}
mul[k]=mul[prime[j]]*mul[i];
}
}
for(int i=1;i<=N-3;i++){
suml[i]=suml[i-1]+mul[i];
}
}
int s[N];
signed main(){
get_prime();
int T;
scanf("%lld",&T);
for(int n=1;n<=N-3;n++){
int l=1,r=0;
while(l<=n){
int t=n/l;
if(!t) break;
int r=n/t;
s[n]+=(r-l+1)*t;
l=r+1;
}
}
while(T--){
int n,m;
scanf("%lld%lld",&n,&m);
if(n>m) swap(n,m);
int ans=0;
int l=1,r=0;
while(l<=n){
int ta=n/l,tb=m/l;
if(!ta || !tb) break;
int r=min(n/ta,m/tb);
ans+=s[ta]*s[tb]*(suml[r]-suml[l-1]);
l=r+1;
}
printf("%lld\n",ans);
}
}
作者:bloss
出处:https://www.cnblogs.com/jinjiaqioi/p/17627668.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效