如果是已知F(x),求f(x)的话,(就是f(x)是被卷函数,F(x)是卷积)
可以利用容斥的方法,也可以利用反演公式,利用反演公式一般起到两个作用,化简方便降低复杂度或者是配出积性函数来线性筛。
直接容斥求的原理如下,复杂度为nlogn .但前提是F(x)已知且易求得。
代码如下
这里是正向推。
for (int i=1;i<=MAX;++i)
for (int j=i<<1;j<=MAX;j+=i)
F[j]-=F[i];
或者是利用反演,乘上一个莫比乌斯函数,这样就可以只考虑素数,并且枚举素数的时候,可以很容易的得到递推关系。
for (int i = 1; i <= N; i++) f[i] = F[i];
for (int i = 0; i < prime_count; i++)
for (int j = N / prime[i]; j >= 1; j--)
f[j * prime[i]] = f[j * prime[i]] - f[j]
举个例子
1 筛完F,直接暴力来。nlogn
for (int i=1;i<=MAX;++i)
for (int j=i<<1;j<=MAX;j+=i)
F[j]-=F[i];
2
nloglogn
for (int i = 1; i <= N; i++) f[i] = F[i];
for (int i = 0; i < prime_count; i++)
for (int j = N / prime[i]; j >= 1; j–)
f[j * prime[i]] = f[j * prime[i]] - f[j]
或者是筛出mu,再
for(int i=1;i<=cnt;i++)
{
for(int j=1;j<=nn/prime[i];j++)
{
f[prime[i]*j]+=mu[j];
}
}
然后这个可以线性筛,但是这不是积性函数,所以,能线性筛的不一定非得是积性函数。
如下
mu[1]=1;
g[1]=1;
for(int i=2;i<N;++i) {
if(g[i]==0) p[++tot]=i,mu[i]=-1,f[i]=1;
for(int j=1;j<=tot&&p[j]<N/i;++j) {
g[i*p[j]]=1;
if(i%p[j]==0) {
f[x]=mu[i];
mu[x]=0;
break;
} else {
f[x]=-f[i]+mu[i];
mu[x]=-mu[i];
}
}
f[i]+=f[i-1];
}
若是f(x)已知,求F(x),枚举倍数就好。复杂度nlogn,但是如果f(x) 是积性函数,线性筛复杂度o(n)。这里本就不需要反演,所以没法乘上mu,也就没法枚举素数。
举个例子
f
(
n
)
f(n)
f(n)=
∑
d
∣
N
\sum_{d|N}
∑d∣Nd
φ
(
n
/
d
)
\varphi(n/d)
φ(n/d)
1
for(int i=1;i<=nn;i++)
{
for(int j=i;j<=nn;j=j+i)
{
f[j]+=phi[i]*(j/i);
}
}
2
for(int i=1;i<=nn;i++)
f[i]=phi[i];
for(int i=2;i<=nn/i;i++)
{
f[i*i]+=phi[i]*i;
for(int j=i+1;j<=nn/i;j++)
{
f[i*j]+=phi[i]*j+phi[j]*i;//+= 可能写成=出错
}
}
然后也可以线性筛。
线性筛在弄得过程中要找到这样几个关系,
f
(
1
)
f(1)
f(1),
f
(
p
)
f( p)
f(p) , ,
f
(
p
k
)
f( p ^ k)
f(pk)与
f
(
p
k
−
1
)
f(p^{k-1})
f(pk−1)的关系。
如下。
g[1]=1;
phi[1]=1;
f[1]=1;//这里f[1]与phi[1]一样,f[1]在下面也筛不到
for(int i=2;i<=nn;i++)
{
if(g[i]==0)
{
prime[++cnt]=i;
phi[i]=i-1;
r[i]=i;
f[i]=i*2-1;
}
for(int j=1;j<=cnt&&prime[j]<=nn/i;j++)
{
g[i*prime[j]]=1;
if(i%prime[j]==0)
{
r[i*prime[j]]=prime[j]*r[i];
phi[i*prime[j]]=prime[j]*phi[i];
if(r[i]==i)
{
f[i*prime[j]]=f[i]*prime[j]+phi[i*prime[j]];
}
else
{
f[i*prime[j]]=f[i/r[i]]*f[prime[j]*r[i]];
}
break;
}
r[i*prime[j]]=prime[j];
phi[i*prime[j]]=phi[prime[j]]*phi[i];
f[i*prime[j]]=f[i]*f[prime[j]];
}
}
再举几个例子。
g[1]=1;f[1]=1;
for(int i=2;i<=MAX;++i)
{
if(!g[i])pri[++tot]=i,f[i]=(i-1ll*i*i%MOD+MOD)%MOD;
for(int j=1;j<=tot&&i*pri[j]<=MAX;++j)
{
g[i*pri[j]]=1;
if(i%pri[j]==0){f[i*pri[j]]=1ll*f[i]*pri[j]%MOD;break;}
else f[i*pri[j]]=1ll*f[i]*f[pri[j]]%MOD;
}
}
待续。
几个枚举倍数的东西。
求约数和,不包括本身,求约数个数则+1 。
void work(int n) {
for (int i = 1; i <= n/i; i++) {
for (int j = i*2; j <= n; j+=i)p[j] += i;
}
}
求约数和,包括本身
void work(int n) {
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j+=i)p[j] += i;
}
}
求欧拉函数
phi[1]=1;
for(int i=2;i<=nn;i++)
{
if(phi[i]==0)
{
for(int j=i;j<=nn;j=j+i)
{
if(phi[j]==0)
phi[j]=j;
phi[j]=phi[j]-phi[j]/i;
}
}
}