数论\to 模范
本文未经说明全是整数,全是整除。
aifoson 括号
diliclate 卷积
符号
一般卷积的形式:
因为 2.,所以枚举的值是要整除
- dlk 卷积满足交换律,结合律
1.易证,因为所有卷积的形式都是对称的。
是u论函数
- 值域,定义域
。
常见数论函数
以上都是完全积性函数。
- 完全积性函数满足
,但是看不懂。
以上都是积性函数。
- 积性函数满足
。
积性函数
,由 可得。 ,由各质因子互质可得。- 两个积性函数的 dlk 卷积还是积性函数。
证明:
🐍 为积性函数, ,记由于 互质,所以 互质,两个求和可以合并: - 若存在
,则称 为 的逆,且 也是积性函数,这可以顺便证明 是积性函数。
的推导
以下默认函数为积性函数。
设两单变量函数
那么有
变形一下
大佬Möbius把
这里有个小技巧,研究一个积性函数,先研究其在质数的幂时的表现。
先看
,由 5., , ,所以 , ,消去 (因为 都等于 ),
再用数学归纳法不难得到
根据 4.,对于
又因为
这下就好理解 了。
莫反公式
A. 嵌入式莫比乌斯反演
证明:
有一个显然的东西:
然后再看这个式子:
展开:
将
从中间可以得到的副产品
但是是最有用的式子。
B. 约数的莫比乌斯反演
,则
证明:
由
C. 倍数的莫比乌斯反演
,则
ben 说做题基本不会用,待补。
一些题目
线性筛会了就可以开始做题了,筛质数的过程中可以顺便按照其定义处理
GCD
记
由 10. 得
考虑
到这里就可以
我们需要一个新东西,整除分块
然后就可以做到
P4450 双亲数
求
题目存在一个隐含的条件,对于能计数的情况,一定有
两边除以
然后就是上题的板子了。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int pr[80003],cnt,n,m,d,ans;
bool isp[1000003];
int mu[1000003];
int premu[1000003];
void sieve(){
premu[1]=mu[1]=1;
for(int i=2;i<=n;i++){
if(!isp[i]) pr[++cnt]=i,mu[i]=-1;
for(int j=1;i*pr[j]<=n;j++){
isp[i*pr[j]]=1;
mu[i*pr[j]]=(i%pr[j]?-mu[i]:0);
if(i%pr[j]==0) break;
}
premu[i]=premu[i-1]+mu[i];
}
}
signed main(){
cin>>n>>m>>d;
if(n<m) swap(n,m);
sieve();
for(int i=1;i<=m/d;i++)
ans+=mu[i]*(n/d/i)*(m/d/i);
cout<<ans;
return 0;
}
P3455 [POI2007] ZAP-Queries
上题带多组询问。
加个数论分块即可,时间复杂度
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int pr[80003],cnt,n,m,d,ans;
bool isp[1000003];
int mu[1000003];
int premu[1000003];
void sieve(){
premu[1]=mu[1]=1;
for(int i=2;i<=50000;i++){
if(!isp[i]) pr[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*pr[j]<=50000;j++){
isp[i*pr[j]]=1;
mu[i*pr[j]]=(i%pr[j]?-mu[i]:0);
if(i%pr[j]==0) break;
}
premu[i]=premu[i-1]+mu[i];
}
}
void solve(){
cin>>n>>m>>d;
if(n<m) swap(n,m);
ans=0; n/=d; m/=d;
for(int l=1,r=0;l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(premu[r]-premu[l-1])*(n/l)*(m/l);
}
cout<<ans<<'\n';
}
int T;
signed main(){
cin>>T; sieve();
while(T--) solve();
return 0;
}
P2522 [HAOI2011] Problem b
可以用二维差分,则答案为
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int pr[80003],cnt,ans;
bool isp[1000003];
int mu[1000003];
int premu[1000003];
void sieve(){
premu[1]=mu[1]=1;
for(int i=2;i<=50000;i++){
if(!isp[i]) pr[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*pr[j]<=50000;j++){
isp[i*pr[j]]=1;
mu[i*pr[j]]=(i%pr[j]?-mu[i]:0);
if(i%pr[j]==0) break;
}
premu[i]=premu[i-1]+mu[i];
}
}
int solve(int n,int m,int d){
if(n<m) swap(n,m);
ans=0; n/=d; m/=d;
for(int l=1,r=0;l<=m;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=(premu[r]-premu[l-1])*(n/l)*(m/l);
}
return ans;
}
int T,a,b,c,d,k;
signed main(){
cin>>T; sieve();
while(T--){
cin>>a>>b>>c>>d>>k;
cout<<solve(b,d,k)-solve(a-1,d,k)-solve(b,c-1,k)+solve(a-1,c-1,k)<<'\n';
}
return 0;
}
P6156 简单题 / 加强版 P6222
題面為加强版。
給出
uint 自然溢出。
对于
P4240 毒瘤之神的考验
给
对 998244353 取模,多测。
拆式子与根号分治思想的极致融合。
设
先要知道一个经典的式子:
然后拆式子
枚举
后面那个直接莫反拆掉,把枚举扔外面
这个式子就很好看了,设
则原式为
所以预处理
由于原式并不好整除分块,也不能暴力预处理全部信息,所以我们只能考虑分治。
设阈值为
否则可以得到
综上,时间复杂度
点击查看代码
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int maxn=1e5+7;
const int B=24;
const int maxb=B+2;
const int N=1e5;
const int mod=998244353;
bool st;
int mu[maxn],phi[maxn],pr[maxn],pcnt;
ll f[maxn],inv[maxn];
bool isp[maxn];
vector<ll>g[maxn],h[maxb][maxb];
bool ed;
void solve(){
int n,m,l=1,r;
cin>>n>>m;
if(n>m) swap(n,m);
ll ans=0;
for(;l<=m/B;l++)
ans=(ans+f[l]*g[l][n/l]%mod*g[l][m/l]%mod)%mod;
for(;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans=(ans+h[n/l][m/l][r]-h[n/l][m/l][l-1]+mod)%mod;
}
cout<<ans<<'\n';
}
signed main(){
cerr<<(&ed-&st)/1048576.0<<" MB\n";
inv[1]=mu[1]=phi[1]=1;
for(int i=2;i<=N;i++){
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
if(!isp[i]) pr[++pcnt]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=pcnt&&i*pr[j]<=N;j++){
isp[i*pr[j]]=1;
if(i%pr[j]==0){
mu[i*pr[j]]=0;
phi[i*pr[j]]=pr[j]*phi[i];
break;
}
mu[i*pr[j]]=-mu[i];
phi[i*pr[j]]=phi[i]*phi[pr[j]];
}
}
for(int i=1;i<=N;i++){
g[i].resize(N/i+2); g[i][0]=0;
for(int j=1;j<=N/i;j++)
g[i][j]=(g[i][j-1]+phi[i*j])%mod;
}
for(int i=1;i<=N;i++)
for(int j=1;j<=N/i;j++)
f[j*i]=(f[j*i]+i*mu[j]*inv[phi[i]]%mod+mod)%mod;
for(int j=1;j<=B;j++){
for(int k=1;k<=B;k++){
h[j][k].resize(N/k+7); h[j][k][0]=0;
for(int i=1;i<=N/k;i++)
h[j][k][i]=(h[j][k][i-1]+f[i]*g[i][j]%mod*g[i][k]%mod)%mod;
}
}
int TEST;
cin>>TEST;
while(TEST--){
solve();
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】