头都给队友们打烂了啊
这玩意还是简单易懂的啊qwq
似乎博客已经变成了笔记博客??
求一类积性函数的前缀和
经典问题有求 μ \mu μ与 ϕ \phi ϕ的前缀和,本文将以这两个函数的前缀和为例
狄利克雷卷积
两个函数 f f f和 g g g的狄利克雷卷积 f ∗ g f*g f∗g即为
( f ∗ g ) ( i ) = ∑ d ∣ i f ( i ) g ( i d ) (f*g)(i)=\sum_{d|i}f(i)g(\frac{i}{d}) (f∗g)(i)=d∣i∑f(i)g(di)
假设当前我们需要求 f ( x ) f(x) f(x)的前缀和 S ( x ) S(x) S(x)
宇宙惯例,一般 n n n很大求不出来所以我们得做一些奇妙的操作
假设我们能弄出来一个简单的积性函数 g ( x ) g(x) g(x)
对其做狄利克雷卷积得到函数 f ∗ g f*g f∗g
( f ∗ g ) ( i ) = ∑ d ∣ i f ( i ) g ( i d ) (f*g)(i)=\sum_{d|i}f(i)g(\frac{i}{d}) (f∗g)(i)=d∣i∑f(i)g(di)
不妨设 ( f ∗ g ) ( x ) (f*g)(x) (f∗g)(x)的前缀和函数为 p r e ( x ) pre(x) pre(x),则有
p r e ( x ) = ∑ i = 1 x ∑ d ∣ i f ( i ) g ( i d ) pre(x)=\sum_{i=1}^x\sum_{d|i}f(i)g(\frac{i}{d}) pre(x)=i=1∑xd∣i∑f(i)g(di)
把后面那个项提出来可以得到
p r e ( x ) = ∑ d = 1 x g ( d ) ∗ ∑ d ∣ i f ( i d ) pre(x)=\sum_{d=1}^{x}g(d)*\sum_{d|i}f(\frac{i}{d}) pre(x)=d=1∑xg(d)∗d∣i∑f(di)
p r e ( x ) = ∑ d = 1 x g ( d ) ∗ ∑ i = 1 ⌊ i d ⌋ f ( i ) pre(x)=\sum_{d=1}^{x}g(d)*\sum_{i=1}^{\lfloor\frac{i}{d}\rfloor}f(i) pre(x)=d=1∑xg(d)∗i=1∑⌊di⌋f(i)
p r e ( x ) = ∑ d = 1 x g ( d ) ∗ S ( ⌊ i d ⌋ ) pre(x)=\sum_{d=1}^{x}g(d)*S(\lfloor\frac{i}{d}\rfloor) pre(x)=d=1∑xg(d)∗S(⌊di⌋)
我们不难得到下面的一个式子
g ( 1 ) S ( n ) = ∑ i = 1 n g ( i ) ∗ S ( ⌊ n i ⌋ ) − ∑ i = 2 n g ( i ) ∗ S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^{n}g(i)*S(\lfloor\frac{n}{i}\rfloor)-\sum_{i=2}^{n}g(i)*S(\lfloor\frac{n}{i}\rfloor) g(1)S(n)=i=1∑ng(i)∗S(⌊in⌋)−i=2∑ng(i)∗S(⌊in⌋)
注意到 S ( i ) = ∑ j = 1 i f ( j ) S(i)=\sum_{j=1}^{i}f(j) S(i)=∑j=1if(j),考虑在狄利克雷卷积中,每个 g ( d ) g(d) g(d)相乘的 f ( i d ) f(\frac{i}{d}) f(di)中 i d \frac{i}{d} di的值域在 [ 1 , n i ] [1,\frac{n}{i}] [1,in]中,故不难得到其实前面是一个狄利克雷卷积和
那么式子可以变为
g ( 1 ) S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( i ) ∗ S ( ⌊ n i ⌋ ) g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^{n}g(i)*S(\lfloor\frac{n}{i}\rfloor) g(1)S(n)=i=1∑n(f∗g)(i)−i=2∑ng(i)∗S(⌊in⌋)
如果狄利克雷卷积的前缀和可以快速求出,且 g g g的前缀和也能快速求出
那么就可以对后面的 S ( i ) S(i) S(i)数论分块,记忆化一发开始gank
如果能预处理前 n 2 3 n^{\frac{2}{3}} n32的前缀和就能做到 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32)
首先能知道一个结论就是
∑ d ∣ n μ ( d ) = [ n = = 1 ] \sum_{d|n}\mu(d)=[n==1] d∣n∑μ(d)=[n==1]
那么我们构造 g ( x ) = 1 g(x)=1 g(x)=1
显然狄利克雷卷积的任意前缀和均为 1 1 1
那么就是要算
S ( n ) = 1 − ∑ i = 2 n g ( i ) ∗ S ( n i ) S(n)=1-\sum_{i=2}^{n}g(i)*S(\frac{n}{i}) S(n)=1−i=2∑ng(i)∗S(in)
那么直接做就好了
又出来一个结论就是
∑ d ∣ n ϕ ( d ) = n \sum_{d|n}\phi(d)=n d∣n∑ϕ(d)=n
证明不妨考虑枚举 [ 1 , n ] [1,n] [1,n]中的数与 n n n的 g c d gcd gcd
同样构造 g ( x ) = 1 g(x)=1 g(x)=1
显然狄利克雷卷积的某个前缀和 i i i即为 i ∗ ( i + 1 ) 2 \frac{i*(i+1)}{2} 2i∗(i+1)
那么就是要算
S ( n ) = ( 1 + n ) ∗ n 2 − ∑ i = 2 n g ( i ) ∗ S ( n i ) S(n)=\frac{(1+n)*n}{2}-\sum_{i=2}^{n}g(i)*S(\frac{n}{i}) S(n)=2(1+n)∗n−i=2∑ng(i)∗S(in)
同样直接做就好了
bzoj3944 sum
即为筛 ϕ \phi ϕ与 μ \mu μ的前缀和
注意 2 31 − 1 2^{31}-1 231−1加一可能会爆 i n t int int
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair
#define pii pair
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(LL x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(LL x){write(x);putchar(' ');}
inline void pr2(LL x){write(x);putchar('\n');}
const int MAXN=5000005;
const int MAXM=50005;
int n,N;
int pr[MAXN],plen,mu[MAXN],phi[MAXN];
bool is[MAXN];
LL pre1[MAXN],pre2[MAXN];
void init()
{
phi[1]=1;mu[1]=1;
for(int i=2;i<MAXN;i++)
{
if(!is[i])pr[++plen]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=plen&&i*pr[j]<MAXN;j++)
{
is[i*pr[j]]=true;
if(!(i%pr[j]))
{
mu[i*pr[j]]=0;phi[i*pr[j]]=phi[i]*pr[j];
break;
}
else mu[i*pr[j]]=-mu[i],phi[i*pr[j]]=phi[i]*(pr[j]-1);
}
}
for(int i=1;i<MAXN;i++)pre1[i]=pre1[i-1]+mu[i],pre2[i]=pre2[i-1]+phi[i];
}
bool vi1[2*MAXM],vi2[2*MAXM];
LL id1[2*MAXM];
int getid(int x){return x<=N?x:n/x+N;}
LL solvemu(int x)
{
if(x<MAXN)return pre1[x];
int u=getid(x);
if(vi1[u])return id1[u];
LL ret=1;vi1[u]=true;
for(int i=2,nxt;i<=x;i=nxt+1)
{
nxt=x/(x/i);
LL s=solvemu(x/i);
ret-=1LL*(nxt-i+1)*s;
if(nxt==x)break;
}
return id1[u]=ret;
}
LL id2[2*MAXM];
LL solvephi(LL x)
{
if(x<MAXN)return pre2[x];
int u=getid(x);
if(vi2[u])return id2[u];
LL ret=1LL*(x+1)*x/2;vi2[u]=true;
for(int i=2,nxt;i<=x;i=nxt+1)
{
nxt=x/(x/i);
LL s=solvephi(x/i);
ret-=1LL*(nxt-i+1)*s;
if(nxt==x)break;
}
return id2[u]=ret;
}
int main()
{
init();
int T=read();while(T--)
{
n=read();N=sqrt(n);
if(n<MAXN){pr1(pre2[n]),pr2(pre1[n]);continue;}
memset(vi1,false,sizeof(vi1));memset(vi2,false,sizeof(vi2));
pr1(solvephi(n));
pr2(solvemu(n));
}
return 0;
}