基础莫比乌斯反演
基础莫比乌斯反演
莫比乌斯函数
对于 \(\mu(n)\)
若 \(n=1\) 则 \(\mu(n)=1\)
若 \(n=p_1\cdot p_2\cdots p_k(\text{其中}\ p_i\ \text{为互异素数})\) 则 \(\mu(n)=(-1)^k\)
否则 \(\mu(n)=0\)
线性筛莫比乌斯函数
inline void get_mu(){
mu[1]=not_p[1]=1;
for(int i=2;i<N;++i){
if(!not_p[i]){
p[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*p[j]<N;++j){
not_p[i*p[j]]=1;
if(i%p[j]==0) break;
else mu[i*p[j]]=-mu[i];
}
}
}
基本公式
so:
还有:
p.s. 后文中除法均默认向下取整
对于约数个数函数 \(d(x)\) 有如下性质:
整除分块
对于
因为有许多 \(\frac ni\) 的值相同,每一个值相同的块最后一个数是 \(\frac {n}{\frac{n}{i}}\) 因此可以把其分成 \(\sqrt n\) 块再预处理
这个式子的结果可以在 \(O(\sqrt{n})\) 的时间内求出
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
P2257 YY的GCD
题意:
求:
思路:
枚举一个 \(k\)
同时除以 \(k\)
已知
so,反演一下
枚举 \(d\),由于 \(d|\gcd(i,j)\),所以 \(i,j\) 均为 \(d\) 的倍数
但过不了,考虑优化
令 \(T=kd\),有
枚举 \(T\),往前提
后面一大部分可以预处理
处理一下就可
注意直接枚举会 \(TLE\)
所以加一个整除分块和\(O2\)就行
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e7+1;
#define int long long
int cnt;
int sum[N],f[N];
int mu[N],p[N];
bool not_p[N];
inline void get_mu(){
mu[1]=not_p[1]=1;
for(int i=2;i<N;++i){
if(!not_p[i]){
p[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*p[j]<N;++j){
not_p[i*p[j]]=1;
if(i%p[j]==0) break;
else mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=cnt;++i)
for(int j=1;p[i]*j<N;++j)
f[j*p[i]]+=mu[j];
for(int i=1;i<N;++i)
sum[i]=sum[i-1]+f[i];
}
inline int solve(int x,int y){
int ans=0;
if(x>y) swap(x,y);
for(int i=1,j=0;i<=x;i=j+1){
j=min(x/(x/i),y/(y/i));
ans+=(sum[j]-sum[i-1])*(x/i)*(y/i);
}
return ans;
}
signed main(){
int T=read();
get_mu();
while(T--) cout<<solve(read(),read())<<endl;
}
P3455 ZAP-Queries
题意:
给你 \(m,n,k\),求
思路:
和之前几乎一摸一样
用一个整除分块搞搞就完事
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=5e4+1;
int sum[N];
int cnt,mu[N],p[N];
bool not_p[N];
inline void get_mu(){
mu[1]=not_p[1]=1;
for(int i=2;i<N;++i){
if(!not_p[i]){
p[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*p[j]<N;++j){
not_p[i*p[j]]=1;
if(i%p[j]==0) break;
else mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<N;++i) sum[i]=sum[i-1]+mu[i];
}
inline int solve(int x,int y,int k){
int ans=0;
if(x>y) swap(x,y);
for(int l=1,r=0;l<=x;l=r+1){
r=min(x/(x/l),y/(y/l));
ans+=(sum[r]-sum[l-1])*(x/(l*k))*(y/(l*k));
}
return ans;
}
signed main(){
get_mu();
int T=read();
while(T--){
int x=read(),y=read(),k=read();
cout<<solve(x,y,k)<<endl;
}
}
P2522 Problem b
题意:
求
思路:
不再推一遍了
但是有一些不同的是,这题多一个容斥
假如 \(ans(b,d,k)\) 是式子
的值
那么最终的结果 \(Ans=ans(b,d,k)-ans(c-1,b,k)-ans(a-1,d,k)+ans(a-1,c-1,k)\)
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=5e4+1;
int sum[N];
int cnt,mu[N],p[N];
bool not_p[N];
inline void get_mu(){
mu[1]=not_p[1]=1;
for(int i=2;i<N;++i){
if(!not_p[i]){
p[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*p[j]<N;++j){
not_p[i*p[j]]=1;
if(i%p[j]==0) break;
else mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<N;++i) sum[i]=sum[i-1]+mu[i];
}
inline int solve(int x,int y,int k){
int ans=0;
if(x>y) swap(x,y);
for(int l=1,r=0;l<=x;l=r+1){
r=min(x/(x/l),y/(y/l));
ans+=(sum[r]-sum[l-1])*(x/(l*k))*(y/(l*k));
}
return ans;
}
signed main(){
get_mu();
int T=read();
while(T--){
int a=read(),b=read(),c=read(),d=read(),k=read();
cout<<solve(b,d,k)-solve(b,c-1,k)-solve(a-1,d,k)+solve(a-1,c-1,k)<<endl;
}
}
P3327 约数个数和
题意:
设 \(d(x)\) 为 \(x\) 的约数个数,给定 \(n,m\),求
思路:
已知
so,要求的就是
直接枚举 \(i,j\) 的因数
反演一下
改为枚举 \(d\)
减少枚举次数
结合一下
接下来预处理一个函数 \(f(x)=\sum_{i=1}^{x}\frac xi\),则
然后整除分块就行
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=5e4+1;
#define int long long
int cnt;
int sum[N],f[N];
int mu[N],p[N];
bool not_p[N];
inline void get_mu(){
mu[1]=not_p[1]=1;
for(int i=2;i<N;++i){
if(!not_p[i]){
p[++cnt]=i;
mu[i]=-1;
}
for(int j=1;j<=cnt&&i*p[j]<N;++j){
not_p[i*p[j]]=1;
if(i%p[j]==0) break;
else mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<N;++i) sum[i]=sum[i-1]+mu[i];
for(int i=1;i<N;++i)
for(int l=1,r;l<=i;l=r+1){
r=i/(i/l);
f[i]+=(r-l+1)*(i/l);
}
}
inline int solve(int x,int y){
int ans=0;
if(x>y) swap(x,y);
for(int l=1,r=0;l<=x;l=r+1){
r=min(x/(x/l),y/(y/l));
ans+=(sum[r]-sum[l-1])*f[x/l]*f[y/l];
}
return ans;
}
signed main(){
int T=read();
get_mu();
while(T--){
int n=read(),m=read();
cout<<solve(n,m)<<endl;
}
}