之前不会用 M a r k d o w n Markdown Markdown,所以坑没有补。
以下除法默认向下去整。
对于一个形如 F n = ∑ d ∣ n f d F_n=\sum_{d|n}f_d Fn=∑d∣nfd的式子,用莫比乌斯反演得到了一个结论: f n = ∑ d ∣ n μ ( d ) ∗ F n / d f_n=\sum\limits_{d|n}μ(d)*F_{n/d} fn=d∣n∑μ(d)∗Fn/d。
证明可以考虑狄利克雷卷积(稍后补上)。
那么 μ μ μ的定义是什么呢?
当 n = 1 n=1 n=1时, μ ( n ) = 1 μ(n)=1 μ(n)=1。
当 n > 1 n>1 n>1时,若 n n n能分为 k k k个互不相等的质因数乘积,则 μ ( n ) = ( − 1 ) k μ(n)=(-1)^k μ(n)=(−1)k;
否则, μ ( n ) = 0 μ(n)=0 μ(n)=0。
同时 μ μ μ是积性函数,因此可以用欧拉筛预处理 μ μ μ。
可是怎么用呢。
我们发现 μ μ μ函数存在一个性质: ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum\limits_{d|n}μ(d)=[n=1] d∣n∑μ(d)=[n=1]。
证明可以考虑狄利克雷卷积(稍后补上)。
好像还是没有什么用(大雾…)?
别着急。
求 ∑ i = 1 n ∑ j = 1 n [ g c d ( i , j ) = 1 ] \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[gcd(i,j)=1] i=1∑nj=1∑n[gcd(i,j)=1]。
对于这样的题怎么做呢?
显然暴力的时间复杂度是: Θ ( n 2 ) \Theta(n^2) Θ(n2)的。
好像很难…
细心的同学可以发现该式中的 g c d ( i , j ) = 1 gcd(i,j)=1 gcd(i,j)=1与 μ μ μ性质 [ n = 1 ] [n=1] [n=1]有些类似,不妨将其套入,得:
∑ i = 1 n ∑ j = 1 n ∑ d ∣ g c d ( i , j ) μ ( d ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{d|gcd(i,j)}μ(d) i=1∑nj=1∑nd∣gcd(i,j)∑μ(d)
更换枚举项,得:
∑ i = 1 n ∑ j = 1 n ∑ d = 1 n μ ( d ) [ d ∣ g c d ( i , j ) ] \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{d=1}^{n}μ(d)[d|gcd(i,j)] i=1∑nj=1∑nd=1∑nμ(d)[d∣gcd(i,j)]
将 ∑ d = 1 n μ ( d ) \sum\limits_{d=1}^{n}μ(d) d=1∑nμ(d)前置,得:
∑ d = 1 n μ ( d ) ∑ i = 1 n ∑ j = 1 n [ d ∣ g c d ( i , j ) ] \sum\limits_{d=1}^{n}μ(d)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[d|gcd(i,j)] d=1∑nμ(d)i=1∑nj=1∑n[d∣gcd(i,j)]
更换枚举项,得:
∑ d = 1 n μ ( d ) ∑ i = 1 n / d ∑ j = 1 n / d [ d ∣ ( g c d ( i , j ) ∗ d ) ] \sum\limits_{d=1}^{n}μ(d)\sum\limits_{i=1}^{n/d}\sum\limits_{j=1}^{n/d}[d|(gcd(i,j)*d)] d=1∑nμ(d)i=1∑n/dj=1∑n/d[d∣(gcd(i,j)∗d)]
化简,得:
∑ d = 1 n μ ( d ) ∑ i = 1 n / d ∑ j = 1 n / d 1 \sum\limits_{d=1}^{n}μ(d)\sum\limits_{i=1}^{n/d}\sum\limits_{j=1}^{n/d}1 d=1∑nμ(d)i=1∑n/dj=1∑n/d1
最后,得:
∑ d = 1 n μ ( d ) ∗ ⌊ n d ⌋ ∗ ⌊ n d ⌋ \sum\limits_{d=1}^{n}μ(d)*\Big\lfloor\dfrac{n}{d}\Big\rfloor*\Big\lfloor\dfrac{n}{d}\Big\rfloor d=1∑nμ(d)∗⌊dn⌋∗⌊dn⌋
可以考虑用整除分块来加速,时间复杂度: Θ ( n ) \Theta(\sqrt{n}) Θ(n)。
以这道题 P 4450 P4450 P4450 双亲数 或P3455 [POI2007]ZAP-Queries的代码为例题目,但求的是 g c d ( i , j ) = k gcd(i,j)=k gcd(i,j)=k的方案,具体可以看下面题表第一题的证明。
#include
#include
#include
#define LL long long
using namespace std;
int prime[1000010],mu[1000010],sum_mu[1000010];
bool bz[1000010];
int n,m,k;
void init(int ma)
{
bz[0]=bz[1]=true;
mu[1]=1;
int t=0;
for(int i=2;i<=ma;i++)
{
if(!bz[i]) prime[++t]=i,mu[i]=-1;
for(int j=1;j<=t&&i*prime[j]<=ma;j++)
{
bz[i*prime[j]]=true;
if(!(i%prime[j]))
{
mu[i*prime[j]]=0;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
for(int i=1;i<=n;i++)
sum_mu[i]=sum_mu[i-1]+mu[i];
}
LL solve(int n,int m,int k)
{
LL sum=0;
n/=k,m/=k;
for(int l=1,r;l<=min(n,m);l=r+1)
{
r=min(n/(n/l),m/(m/l));
sum+=((LL)n/l)*((LL)m/l)*((LL)sum_mu[r]-sum_mu[l-1]);
}
return sum;
}
int main()
{
scanf("%d %d %d",&n,&m,&k);
init(max(n,m));
printf("%lld",solve(n,m,k));
}
重点来了。
我们在化简式子时多考虑 ∑ , ∏ \sum,\prod ∑,∏的性质,尝试化简。如果化简出形似 g c d ( i , j ) = 1 gcd(i,j)=1 gcd(i,j)=1的式子,可以考虑带入 μ μ μ的性质,再化简即可。
一般都需要用整除分块的套路,同时,一些题目也需要预处理一些可以被证明的积性函数。
题表 |
---|
luogu P2522 [HAOI2011]Problem b |
luogu P2398 GCD SUM |
luogu P1829 [国家集训队]Crash的数字表格 / JZPTAB |
luogu P2257 YY的GCD |
luogu P3327 [SDOI2015]约数个数和 |
luogu P3312 [SDOI2014]数表 |
luogu P3768 简单的数学题 |
luogu P4917 天守阁的地板 |
luogu P3704 [SDOI2017]数字表格 |
luogu P4318 完全平方数 |
[SPOJ] DIVCNT2 - Counting Divisors |