摘自peng-ym的博客
整除分块
(sum_{i=1}^n lfloor {frac n i} floor)
朴素 (O(n)) , 整除分块 (O(sqrt n))
显然有许多连续的 (lfloor {frac n i} floor) 值是一样的。可以发现,每个块的最后一个数是 (frac n {lfloor frac n i floor })
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
有时推出的柿子不一定是裸的板子,可能与一些积性函数相乘( (mu),(phi)...),
此时需要对这些函数统计前缀和,这样跳过一个区间时就乘上一个区间的函数值。(?)
积性函数&狄利克雷卷积
以后我也会卷啦!
积性函数:
定义:
如果 (gcd(x,y)=1) 并且 (f(xy)=f(x)·f(y)) 则 (f(n)) 是积性函数。
特别的,对于任意 (x,y) 满足 (f(xy)=f(x)·f(y)) 的是完全积性函数。
e.g.
完全积性
-
一元函数:(epsilon (x)=[x=1]) 是积性函数的单位元(可以随便卷在一起和去掉)
-
常数函数:(1(x)=1) 好像也有用字母 (I) 的。
-
单位函数:(id(x)=x)
积性
-
欧拉函数:(phi(x)=sum_{i=1}^x [gcd(x,i)=1])
-
约数个数函数:(d(x)=sum_{d|n} 1)
-
约数和函数: (sigma(n)=sum_{d|n} d)
-
莫比乌斯函数:……
性质:
如果 (f(x)) 是积性函数,那么 (h(x)) 也是:
如果 (f(x)) 和 (g(x)) 是积性函数,那么 (h(x)) 也是:
狄利克雷卷积
定义:
两个数论函数 (f) 和 (g) 的狄利克雷卷积 ((f*g)) 为
性质:
满足交换律和结合律和分配率。自己卷自己是自己。
莫比乌斯反演
莫比乌斯函数
-
符号:(mu) .
-
定义:
[ mu(d)=left{ egin{array}{rcl} 1 & & {d=1}\ (-1)^k & & {d=Pi_{i=1}^k p_i 且 p_i 为互异素数时}\ 0 & & {d 的一个质因子次数ge 2}\ end{array} ight. ] -
性质:
- 对于任意 (nin {N}^+),(mu*1=epsilon (sum_{d|n} mu(d)=[n=1])) 常用性质
考虑非0的 (mu(d)) 的和。
设 (n)有 (k) 个质因子,有 (2^k) 个因子,有 (C_{k,i}) 个的有 (i) 个质因子,
(ans=C(k,0)-C(k,1)+C(k,2)-C(k,3)+...=sum_{i=0}^k (-1)^iC(k,i))
二项式定理: ((x+y)^n=sum C(n,i)x^iy^{(n-i)})
(ans=(-1+1)^k=0^k)
得证。-
对于任意 (nin N^+),
[sum_{d|n} frac {mu(d)} d=frac {phi(n)} n ]Proof
[首先有结论sum_{d|n} phi(d)=n(id=phi*I)\ 证明:\ frac 1 n,frac 2 n,frac 3 n,...,frac n n \化简这些分数 分母是 d (d|n)\ 每个分母d对应的分子个数就是 phi(d) ][id=phi*I\ id*mu=phi*I*mu\ id*mu=phi*epsilon\ id*mu=phi\ phi=id*mu\ phi(n)=sum_{d|n} mu(d)*frac n d\ sum_{d|n} phi(d)=n(id=phi*I) ]
-
代码
void getmu(int n){ mu[1]=1; for(int i=2;i<=n;i++){ if(!vis[i]) { p[++cnt]=i; mu[i]=-1; } for(int j=1;j<=cnt&&p[j]*i<=n;j++){ vis[p[j]*i]=1; if(i%p[j]==0) break; else mu[p[j]*i]=-mu[i]; } } }
(O(n))
莫比乌斯反演
莫比乌斯反演定理
(F(n)) 和 (f(n)) 是定义在 (N) 上的两个函数,并且满足条件
有结论:
Proof:
[sum_{d|n}mu(d)F(lfloorfrac{n}{d} floor)\=sum_{d|n}mu(d)sum_{i|lfloorfrac{n}{d} floor}f(i)\ =sum_{i|n}f(i)sum_{d|lfloorfrac{n}{i} floor}mu(d)\=f(n) ]
Proof2:
噫!好!让我们用狄利克雷卷积来证明一下。
已知
[F(n)=sum_{d|n} f(d) ]求证
[f(n)=sum_{d|n} mu(d)·F(frac n d) ][转化一下:\ 已知:\ F(n)=sum_{d|n} f(d)\ F(n)=sum_{d|n} f(d)·1(frac n d)\ F=f*1\ 求证:\ f(n)=sum_{d|n} mu(d)·F(frac n d)\ f(n)=mu *F\ 证明:\ F*mu=f*1*mu=f*epsilon=f\ 比上面那坨好多了qwq ]
莫比乌斯反演有另一种可能更好用的形式:
条件:
结论:
证明:
令 (k=frac d n)
(f(n)=sum_{k=1}^{inf} mu(k)F(nk)=sum_{k=1}^{inf} mu(k) sum_{nk|t} f(t)=sum_{n|t} f(t) sum_{k|frac t n} mu(k))
当且仅当 (frac t n =1) ,即 (t=n) 时, (sum_{k|frac t n}mu(k)=1)
∴ (sum_{n|t} f(t) sum_{k|frac t n}mu (k)=f(n))
$F(n)=sum_{n|d} f(d) $
(f(n)=sum_{n|d}mu(lfloor frac{d}{n} floor)F(d))
习题
LG2257 - YY的GCD
给定 (N,M) ,求 (1le x le N,1le yle M) 且 (gcd(x,y)) 为质数的 ((x,y)) 有多少对?
(ans=sum_{x=1}^n sum_{y=1}^m [gcd(x,y)=prime])
第一道莫反不会做 列完这个柿子就壮烈牺牲了。
设 (f(d)) 为 (gcd(i,j)=d) 的个数
(F(n)) 为 (gcd(i,j)=n) 和 (n) 的倍数的个数。
(套路)
(f(d)=sum_{x=1}^n sum_{y=1}^m [gcd(x,y)=d])
(F(n)=sum_{n|d} f(d)=lfloor frac N n floor lfloor frac M n floor)
(f(n)=sum_{n|d}mu(lfloor frac{d}{n} floor)F(d))
(ans=sum_{pin prime} f(p))
(ans=sum_{pin prime} sum_{p|d}mu(lfloor frac{d}{p} floor)F(d))
(ans=sum_{pin prime} sum_{d=1}^{min(frac n p,frac m p)} mu(d)F(dp))
(ans=sum_{pin prime} sum_{d=1}^{min(frac n p,frac m p)} mu(d)lfloor frac n {dp} floor lfloorfrac m {dp} floor)
(ans=sum_{T=1}^{min(n,m)} lfloor frac n T floor lfloor frac m T floor imes(sum_{t|T,tin prime} mu(lfloor frac T t floor)))
最后一坨东西可以预处理 前面那坨整除分块
void getmu(){
mu[1]=1;
for(int i=2;i<=N;i++){
if(!fl[i]) p[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&p[j]*i<=N;j++){
fl[p[j]*i]=1;
if(i%p[j]==0) continue;
mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=cnt;i++)
for(int j=1;p[i]*j<=N;j++)
f[p[i]*j]+=mu[j];//T=p[i]*j t=p[i]
for(int i=1;i<=N;i++) sum[i]=sum[i-1]+f[i];
return;
}//预处理前面那坨
long long solve(int a,int b){
long long ans=0;
for(int l=1,r;l<=a;l=r+1){
r=min(a/(a/l),b/(b/l));
ans+=1ll*(sum[r]-sum[l-1])*(a/l)*(b/l);
}
return ans;
}//预处理后面那坨
int main(){
int t; scanf("%d",&t);
getmu();
while(t--){
scanf("%d%d",&n,&m);
if(n>m) swap(n,m);
printf("%lld
",solve(n,m));
}
return 0;
}
草,题解说入门的不适合做这题(
LG2522 - [HAOI2011]Problem b
(n) 次询问,每次询问有多少个数对 ((x,y)) 满足 (ale xle b,cle yle d) 且 $gcd(x,y)=k $ 所有东西都是 (5 imes 10^4)
草 这好像是前一题的低配啊,这确定没搞反吗。
void getmu(){
mu[1]=1;
for(int i=2;i<=N;i++){
if(!fl[i]) p[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&p[j]*i<=N;j++){
fl[p[j]*i]=1;
if(i%p[j]==0) continue;
mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=N;i++) sum[i]=sum[i-1]+mu[i];
return;
}
long long solve(int a,int b,int k){
if(a>b) swap(a,b);
long long ans=0;
for(int l=1,r;l<=a;l=r+1){
r=min(a/(a/l),b/(b/l));
ans+=1ll*(sum[r]-sum[l-1])*(a/(1ll*l*k))*(b/(1ll*l*k));
}
return ans;
}
int main(){
int t; scanf("%d",&t);
getmu();
while(t--){
int a,b,c,d,k;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("%lld
",solve(b,d,k)-solve(a-1,d,k)-solve(b,c-1,k)+solve(a-1,c-1,k));
}
return 0;
}
显然顺序搞反了。。
[LG3455 - POI2007]ZAP-Queries
倒序开题,双倍经验,这是好的。这是前一道题的前置题。是 (a=1,b=1) 的情况。
[LG3327 - SDOI2015]约数个数和
设 (d(x)) 为 (x) 的约数个数,给定 (n,m) ,求 (sum_{i=1}^n sum_{j=1}^m d(ij))
void init(){
for(int i=1;i<=N;i++){
for(int l=1,r;l<=i;l=r+1){
r=i/(i/l);
s[i]+=1ll*(r-l+1)*(i/l);
}
}//预处理s
mu[1]=1;
for(int i=2;i<=N;i++){
if(!vis[i]) p[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&p[j]*i<=N;j++){
vis[i*p[j]]=1;
if(i%p[j]==0) continue;
mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=N;i++) sum[i]=sum[i-1]+mu[i];
return;
}
int main(){
int t; scanf("%d",&t);
init();
while(t--){
int n,m; scanf("%d%d",&n,&m);
if(n>m) swap(n,m);
ll ans=0;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans+=1ll*(sum[r]-sum[l-1])*s[n/l]*s[m/l];
}//分块求
printf("%lld
",ans);
}
return 0;
}
LG1829 [国家集训队]Crash的数字表格 / JZPTAB
求 (ans=sum_{i=1}^n sum_{j=1}^m lcm(i,j)) (n,mle 10^7)
void init(){
mu[1]=1;
for(int i=2;i<=N;i++){
if(!vis[i]){ mu[i]=-1; p[++cnt]=i; }
for(int j=1;j<=cnt&&p[j]*i<=N;j++){
vis[p[j]*i]=1;
if(i%p[j]==0) continue;
mu[p[j]*i]=-mu[i];
}
}
for(int i=1;i<=N;i++)
sum[i]=(sum[i-1]+1ll*mu[i]%mod*i%mod*i%mod)%mod;
return;
}
int calc(int x){ return (1ll*x*(x+1)/2)%mod; }
int main(){
scanf("%d%d",&n,&m);
if(n>m) swap(n,m);
init();
for(int d=1;d<=n;d++){
int a=n/d,b=m/d,ret=0;
for(int l=1,r;l<=a;l=r+1){
r=min(a/(a/l),b/(b/l));
ret=(ret+1ll*(sum[r]-sum[l-1])*calc(n/(d*l))%mod*calc(m/(d*l))%mod)%mod;
}
ans=(ans+1ll*ret*d%mod)%mod;
}
printf("%d
",(ans+mod)%mod);
return 0;
}
SP5971 LCMSUM - LCM Sum
(T) 次询问,每次询问给定 (n) ,求 (sum_{i=1}^n lcm(i,n))
void init(){
phi[1]=1;
for(int i=2;i<=N;i++){
if(!vis[i]) phi[i]=i-1,p[++cnt]=i;
for(int j=1;j<=cnt&&p[j]*i<=N;j++){
vis[p[j]*i]=1;
if(i%p[j]==0){
phi[p[j]*i]=phi[i]*p[j];
break;
}
phi[p[j]*i]=phi[i]*(p[j]-1);
}
}
for(int i=1;i<=N;i++){
ll tmp=1ll*phi[i]*i/2;
if(i==1) tmp=1;
for(int j=1;j*i<=N;j++) f[j*i]+=tmp;
}
return;
}
int main(){
scanf("%d",&t);
init();
while(t--){
scanf("%d",&n);
printf("%lld
",1ll*f[n]*n);
}
return 0;
}
咕咕咕