背景:
之前不会用
,所以坑没有补。
定义:
以下除法默认向下去整。
对于一个形如
的式子,用莫比乌斯反演得到了一个结论:
。
证明可以考虑狄利克雷卷积(稍后补上)。
那么
的定义是什么呢?
当
时,
。
当
时,若
能分为
个互不相等的质因数乘积,则
;
否则,
。
同时
是积性函数,因此可以用欧拉筛预处理
。
用法:
可是怎么用呢。
我们发现
函数存在一个性质:
。
证明可以考虑狄利克雷卷积(稍后补上)。
好像还是没有什么用(大雾…)?
别着急。
例题:
求 。
对于这样的题怎么做呢?
显然暴力的时间复杂度是:
的。
好像很难…
细心的同学可以发现该式中的
与
性质
有些类似,不妨将其套入,得:
更换枚举项,得:
将
前置,得:
更换枚举项,得:
化简,得:
最后,得:
可以考虑用整除分块来加速,时间复杂度:
。
代码:
以这道题 双亲数 或P3455 [POI2007]ZAP-Queries的代码为例题目,但求的是 的方案,具体可以看下面题表第一题的证明。
#include<cstdio>
#include<algorithm>
#include<cstring>
#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));
}
总结
重点来了。
我们在化简式子时多考虑
的性质,尝试化简。如果化简出形似
的式子,可以考虑带入
的性质,再化简即可。
一般都需要用整除分块的套路,同时,一些题目也需要预处理一些可以被证明的积性函数。