数论算法总结

数论算法

快速乘

ll mul(ll a,ll b,ll mod)
{
	ll tmp=a*b-(ll)((long double)a/mod*b+0.5)*mod;
	return tmp<0?tmp+mod:tmp;
}

同余系相关

Exgcd

[ax+by=c ]

存在 $ax+by=gcd(a,b)因为 $所以 (a x_{1}+b y_{1}=b x_{2}+left(a-left(leftlfloorfrac{a}{b} ight floor imes b ight) ight) y_{2})

(a y_{2}+b x_{2}-leftlfloorfrac{a}{b} ight floor imes b y_{2}=a y_{2}+bleft(x_{2}-leftlfloorfrac{a}{b} ight floor y_{2} ight))

所以 (x_{1}=y_{2}, y_{1}=x_{2}-leftlfloorfrac{a}{b} ight floor y_{2})

递归求解,终止时必然有 (x=1,y=0)

解集为 ({(x,y)|x=x_1+kfrac{b}{gcd(a,b)},y=y_1-kfrac{a}{gcd(a,b)}})

void exgcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0){x=1,y=0;return;}
    exgcd(b,a%b,x,y);
    ll t=y;y=x-y*(a/b),x=t;
}

ExCRT

[left{egin{array}{l} {x equiv b_{1}left(mod a_{1} ight)} \ {x equiv b_{2}left(mod a_{2} ight)} \ {cdots} \ {x equiv b_{n}left(mod a_{n} ight)} end{array} ight. ]

每次合并两个方程 (x equiv b_{1}left(mod a_{1} ight))(x equiv b_2left(mod a_2 ight))

存在 (x=b_1+a_1k_1,x=b_2+a_2k_2 o b_1+a_1k_1=b_2+a_2k_2)

求解二元一次方程 (a_1k_1-a_2k_2=b_2-b_1)

(cequiv k_1(mod frac{a_2}{gcd(a_1,a_2)}))

可得新的方程为

(x equiv ca_{1}+b_{1}(mod frac{a_1a_2}{gcd(a_1,a_2)}))

ll ExCRT(ll *a,ll *p,const int &n)
{
	ll A=a[1],M=p[1],k1,k2;
	for(int i=2;i<=n;i++)
	{
		ll c=((a[i]-A)%p[i]+p[i])%p[i],g=gcd(M,p[i]);
		if(c%g)return -1;
		exgcd(M,p[i],k1,k2);
		k1=mul(k1,c/g,p[i]);
		ll now=M/g*p[i];
		A=(mul(k1,M,now)+A)%now,M=now;
	}
	return (A%M+M)%M;
}

ExBSGS

[a^xequiv b(mod p) ]

根据欧拉定理 (a^{phi(p)}equiv 1(mod p))(p)(a) 互质。

可以在 (O(p)) 的时间复杂度解决这个问题。

但是对于一般情况 (p) 不一定与 (a) 互质。

(g=gcd(a,p))

(g|b) ,则存在

[a^{x-1}frac{a}{g}equiv frac{b}{g}(modfrac{p}{g}) ]

否则,若 (b=1) 解为 (x=0)(b≠1) 无解

由 $frac{a}{g} $ 与 $ frac{p}{g}$ 互质可得

[a^{x-1}equiv frac{b}{g}(frac{a}{g})^{-1}(modfrac{p}{g}) ]

继续分解直到 (g=1) 为止

[a^{x-t}equivfrac{b}{prod g_i}(frac{a^t}{prod g_i})^{-1}(mod {frac{p}{prod g_i}}) ]

这时候需要特判 (a^1,a^2,...,a^t) 是否存在与 (b) 同余的数。

因为 (g=1) ,所以原问题就被转换为了 (a^xequiv b(mod{p})),且 (a,p) 互质。

考虑分块求解这个问题,设 (n=lceilsqrt{q} ceil)

显然可以使用 (xn-y,x,yleq n) 来表示一个小于 (p) 的数

(a^{xn}equiv ba^{y}(mod{p}))

只需要将所有的 (ba^{y}) 存入Hash表中,再对所有 (y) 查询合法的值。

int ExBSGS(int a,int b,int p)
{
	if(a==0&&b==0)return 1;
	if(a==0)return -1;
	if(b==1)return 0;
	unordered_map<int,int>vis;
	int g=gcd(a,p),mag=1,t=0;
	while(g!=1)
	{
		if(b%g)return -1;
		++t,p/=g,b/=g,mag=mag*1LL*(a/g)%p;
		if(mag==b)return t;
		g=gcd(a,p);
	}
	vis.clear();
	int n=sqrt(p)+1;
	for(int i=0,m=b;i<n;i++,m=m*1LL*a%p)vis[m]=i;
	a=Pow(a,n,p);
	for(int i=1,m=mag*1LL*a%p;i<=n;i++,m=m*1LL*a%p)if(vis.count(m))return i*n-vis[m]+t;
	return -1;
}

Lucas

[C_{n}^{m}equiv C_{lfloorfrac{n}{p} floor}^{lfloorfrac{m}{p} floor} cdot C_{nmod p}^{mmod p}(mod{p}) ]

首先可以观察得出 (C_p^i=frac{p}{i}C_{p-1}^{i-1}) ,所以显然有 (C_p^iequiv0(mod p))

[(1+x)^p=sum_{i=0}^p C_n^ix^i\ (1+x)^pequiv C_p^0x^0+C_p^px^pequiv1+x^p(mod p) ]

(n=a_0+a_1p+a_2p^2+a_3^p+...+a_kp^k,m=b_0+b_1p+b_2p^2+...+b_kp^k)

lucas定理也可以表示为一下形式

[C_n^mequivprod_{i=0}^kC_{a_i}^{b_i}(mod p) ]

((1+x)^n)(x^m) 的系数显然为 (C_m^n)

[(1+x)^{n}=prod_{i=0}^{k}left((1+x)^{p^{i}} ight)^{a_{i}}\ (1+x)^nequivprod_{i=0}^k(1+x^{p^i})^{a_i}(mod p) ]

可得 (x^m) 的系数为 $prod_{i=0}kC_{a_i}{b_i} $

因为 (m=b_0+b_1p+b_2p^2+...+b_kp^k)(exists a_i<b_i)(m) 无法被表示系数为 (0)

得证。

int lucas(int n,int m,int mod){if(n==0&&m==0)return 1;return lucas(n/mod,m/mod,mod)*1LL*C(n%mod,m%mod,mod)%mod;}

Exlucas

[C_n^mmod p,pleq 10^6 ]

这里的 (p) 可能不是质数

根据唯一分解定理 (p=p_1^{k_1}p_2^{k_2}...p_t^{k_t})

(forall k_i,k_i=1) 可以直接对于每个质数使用lucas求解,再使用CRT合并。

否则需要求解子问题 (C_n^m mod p_i^{k_i}) 再使用CRT合并。

[C_n^m=frac{n!}{m!(n-m)!}=frac{frac{n!}{p^a}}{frac{m!}{p^b}frac{(n-m)!}{p^c}}p^{a-b-c} ]

只需要解决 (frac{n!}{p^a}mod p^k) ,其中 (a)(n!) 包含的 (p) 的次数。

考虑将 (n!) 分组,(n!=(p imes2p imes 3p imes 4p imes... imeslfloorfrac{n}{p} floor p) imes1 imes2 imes... imes(p-1) imes(p+1) imes... imes(2p-1) imes...)

可以发现后面是模 (p^k) 是循环的,可以通过预处理求出

[n!equivlfloorfrac{n}{p} floor!cdot p^{lfloorfrac{n}{p} floor}(prod_{i,(i,p)=1}^{p^k}{i})^{lfloorfrac{n}{p^k} floor}prod_{i,(i,p)=1}^{n mod p^k}i(mod p^k) ]

前面的 (lfloorfrac{n}{p} floor!) 是一个子问题递归求解即可。

复杂度 (O(plog n))

ll mul(ll a,ll b,ll mod)
{
   ll tmp=a*b-(ll)((long double)a/mod*b+0.5)*mod;
   return tmp<0?tmp+mod:tmp;
}
ll Pow(ll a,ll k,ll mod)
{
   ll ret=1;
   while(k){if(k&1)ret=ret*1LL*a%mod;k>>=1,a=a*1LL*a%mod;}
   return ret;
}
ll fact(ll n,ll p,ll pk)
{
   if(!n)return 1;
   ll ans=1;
   for(ll i=1;i<pk;i++)if(i%p)ans=ans*1LL*i%pk;
   ans=Pow(ans,n/pk,pk);
   for(ll i=1;i<=n%pk;i++)if(i%p)ans=ans*1LL*i%pk;
   return ans*1LL*fact(n/p,p,pk)%pk;
}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void exgcd(ll a,ll b,ll &x,ll &y)
{
   if(b==0)return x=1,y=0,void();
   exgcd(b,a%b,x,y);
   ll t=x;x=y,y=t-y*(a/b);
}
ll inv(ll x,ll p)
{
   ll t1,t2;
   exgcd(x,p,t1,t2);
   return (t1%p+p)%p;
}
ll getpower(ll x,ll p)
{
   ll c=0;
   while(x)c+=x/p,x/=p;
   return c;
}
ll C(ll n,ll m,ll p,ll pk)
{
   ll pa=getpower(n,p)-getpower(m,p)-getpower(n-m,p);
   return Pow(p,pa,pk)*1LL*fact(n,p,pk)%pk*inv(fact(m,p,pk),pk)%pk*inv(fact(n-m,p,pk),pk)%pk;
}
ll ExCRT(ll *a,ll *p,const ll&n)
{
   ll A=a[1],M=p[1],k1,k2;
   for(ll i=2;i<=n;i++)
   {
   	ll c=((a[i]-A)%p[i]+p[i])%p[i],g=gcd(M,p[i]);
   	if(c%g)return -1;
   	exgcd(M,p[i],k1,k2);
   	k1=mul(k1,c/g,p[i]);
   	ll now=M/g*p[i];
   	A=(mul(k1,M,now)+A)%now,M=now;
   }
   return (A%M+M)%M;
}
ll a[30],b[30];
ll cnt;
ll exlucas(ll n,ll m,ll p)
{
   cnt=0;
   ll lim=sqrt(p);
   for(ll i=2;i<lim;i++)
   {
   	if(p%i)continue;
   	ll t=1;while(p%i==0)p/=i,t*=i;
   	a[++cnt]=t,b[cnt]=C(n,m,i,t);
   }
   if(p>1)a[++cnt]=p,b[cnt]=C(n,m,p,p);
   return ExCRT(b,a,cnt);
}

二次剩余

无特殊说明 (p) 均为奇素数。

对于 (p,n) ,若存在 (x) ,满足

[x^2equiv n(mod p) ]

则称 (n) 为模 (p) 意义下的二次剩余

勒让德符号

[left(frac{n}{p} ight)= egin{cases} 1,&n ext{在模$p$意义下是二次剩余}\ -1,&n ext{在模$p$意义下是非二次剩余}\ 0,&nequiv0pmod p end{cases} ]

欧拉判别准则

[left({nover p} ight)equiv n^{p-1over 2}pmod{p} ]

证明:

(n) 为模 (p) 意义下的二次剩余,即存在 (x^2equiv n(mod p)) ,由费马小定理可得 (x^{p-1}equiv 1(mod p)),显然 (n^{frac{p-1} {2}}equiv 1(mod p))

(n) 为模 (p) 意义下的非二次剩余,假设存在 (x^2equiv n(mod p)) ,此时 (x^{p-1}equiv -1(mod p)) ,由费马小定理可知 (x) 不存在

若 $nequiv 0(mod p) $ ,显然成立。

Cipolla

定理1

[n^2equiv (p-n)^2pmod{p} ]

定理2

(p) 的二次剩余与非二次剩余的个数均为 (frac{p-1}{2}) (不考虑 (0) 的情况下)。

证明:

我们只考虑所有的 (n^2),假设有 (x≠y)(x^2≡y^2(mod p)),则 (p∣(x^2−y^2)),即 (p∣(x−y)(x+y)),若(p∤(x−y)),则 (p∣(x+y)),故 (x+y≡0(mod p)),也就是不同的 (x^2) 共有 $frac{p-1}{2} $ 个,即二次剩余有个 (frac{p-1}{2}) 个。

算法流程
  1. 判断给定的数 (x) 是否是二次剩余。
  2. 随机一个 (a),使其满足 ((a^2−x)) 是二次非剩余。
  3. (omega^2equiv (a^2-x)pmod{p}) ,取 (yequiv left(a+{omega} ight)^{p+1over 2}) 为其中一个可行解。

证明:

[omega^{p-1}equiv (omega^2)^{p-1over 2}equiv (a^2-x)^{p-1over 2}equiv -1pmod{p} ]

[(a+b)^nequiv a^n+b^npmod{p} ]

[egin{aligned} x^2&equiv(a+omega)^{p+1}\ &equiv(a+omega)^p(a+omega)\ &equiv(a^p+omega^p)(a+omega)\ &equiv(a-omega)(a+omega)\ &equiv a^2-omega^2\ &equiv a^2-(a^2-n)\ &equiv npmod p end{aligned} ]

int mod,w;
struct Complex
{
	int a,b;
	Complex(int A=0,int B=0){a=A,b=B;}
	Complex operator * (const Complex &t)const
	{
		return Complex((a*1LL*t.a+b*1LL*t.b%mod*w)%mod,(a*1LL*t.b+b*1LL*t.a)%mod);
	}
}; 
int Pow(int a,long long k)
{
	int ret=1;
	while(k){if(k&1)ret=ret*1LL*a%mod;k>>=1,a=a*1LL*a%mod;}
	return ret;
}
int Pow(Complex a,long long k)
{
	Complex ret=Complex(1,0);
	while(k){if(k&1)ret=ret*a;k>>=1,a=a*a;}
	return ret.a;
}
int Sqrt(int x)
{
	if(!x)return 0;
	if(Pow(x,(mod-1)>>1)==mod-1)return -1;
	while(true)
	{
		int a=rand()*1LL*rand()%mod;
		w=(a*1LL*a%mod+mod-x)%mod;
		if(Pow(w,(mod-1)>>1)==mod-1)return Pow(Complex(a,1),(mod+1)>>1);
	}
}

素数分解相关

Miller-Rabin

判断 (q) 是否为素数((qleq 10^{18})

根据费马小定理,当 (a mod q ≠0)(q) 为质数时,(a^{q-1}≡1 (mod q))

而当 (q) 不是质数时,不一定成立

因此就有了一个想法:随机一些 (a) ,对每一个 (a) 验证 ,如果有一个错误那么它一定是合数

但是,存在这样一类合数 (q) ,对于 (1≤a<q) 上面的式子都成立,比如 (561)

二次探测定理

如果 $x^2≡1(mod p) $,那么 (x≡1(mod p)) 或者 (x≡p-1(mod p)) ,这里 (p) 是质数。

可以发现对于合数,有一定概率不成立。

在检验时,如果 (a^{q-1}≡1(mod q))(2|(q-1)) ,则下一步计算 (a ^{frac{q-1}{2}} mod q) ,如果算出来不是 (1)(q-1) ,那么 (q) 是合数,如果算出来是 (1) 并且 (2|frac{q-1}{2}) ,则继续计算 (frac{q-1}{4}) ,直到出现奇数或者算出 (q-1)

ll mul(ll a,ll b,ll mod)
{
	ll tmp=a*b-(ll)((long double)a/mod*b+0.5)*mod;
	return tmp<0?tmp+mod:tmp;
}
ll Pow(ll a,ll k,ll mod)
{
	ll ret=1;
	while(k){if(k&1)ret=mul(ret,a,mod);k>>=1,a=mul(a,a,mod);}
	return ret;
}
const int tprim[10]={0,2,3,5,7,11,13,17,19,23};
bool Miller_Rabin(ll x)
{
    if(x<2)return 0;
    ll k=x-1,cnt=0;
    while(!(k&1))k>>=1,++cnt;
    for(int i=1,j;i<=9;i++)
	{
		if(tprim[i]==x)return 1;
        if(Pow(tprim[i],x-1,x)!=1)return 0; 
        ll now=Pow(tprim[i],k,x);
        if(now==1||now==x-1)continue;
        now=mul(now,now,x);
        for(j=1;j<=cnt;++j,now=mul(now,now,x))if(now==x-1)break;	
        if(j>cnt)return 0;
    }
    return 1;
}

递归改成递推,这样复杂度是 (O(klog n))

莫比乌斯反演

莫比乌斯反演函数

[mu(n)= egin{cases} 1& n=1\ (-1)^k& n=prod_{i=1}^kp_i\ 0& ext{其余情况} end{cases} ]

性质

[sum_{d|n}mu(d)=[n=1] ]

莫比乌斯反演定理

若函数 (F(n)) 满足

[F(n)=sum_{d|n}f(d) ]

则存在

[f(n)=sum_{d|n}mu(d)F(frac{n}{d}) ]

证明:

[sum_{d|n}mu(d)F(frac{n}{d})=sum_{d|n}mu(d)sum_{i|frac{n}{d}}f(i)=sum_{i|n}f(i)sum_{d|frac{n}{i}}mu(d)=f(n) ]

考虑 (f(i)) 的系数可以很简单地得到证明。


推论:

若函数 (F(d)) 满足

[F(d)=sum_{i=1}^{lfloorfrac{L}{d} floor}f(icdot d) ]

则存在

[f(d)=sum_{i=1}^{lfloorfrac{L}{d} floor}mu(i)F(icdot d) ]

证明:

[sum_{i=1}^{lfloorfrac{L}{d} floor}mu(i)F(icdot d)=sum_{i=1}^{lfloorfrac{L}{d} floor}mu(i)sum_{j=1}^{lfloorfrac{L}{icdot d} floor}f(icdot jcdot d)=sum_{k=1}^{lfloorfrac{L}{d} floor}f(kcdot d)sum_{i|k}mu(i)=sum_{k=1}^{lfloorfrac{L}{d} floor}f(kcdot d)[k=1]=f(d) ]

考虑每个 (f(kcdot d)) 的系数被贡献时满足 (icdot j=k),显然 (i)(k) 的约数,被贡献的系数值为 (mu(i))

这个推论可以很简单地用于求解类似 (sum_{i=1}^nsum_{j=1}^n[gcd(i,j)=d]) 问题

一些例题

基础的套路不在过多阐述。

Problem 1.

[sum_{i=1}^nsum_{j=1}^nfrac{ij}{gcd(i,j)}\ ]

(f(d)) 满足 (满足 (gcd(i,j)=d)(frac{ij}{d}) 的和)

[f(d)=sum_{i=1}^nsum_{j=1}^n frac{ij}{d}[gcd(i,j)=d]=sum_{i=1}^{lfloorfrac{n}{d} floor}sum_{j=1}^{lfloorfrac{n}{d} floor} ijd[gcd(i,j)=1] ]

显然

[ans=sum_{d=1}^nf(d) ]

由莫比乌斯反演的性质可得

[sum_{d=1}^ndsum_{i=1}^{lfloorfrac{n}{d} floor}sum_{j=1}^{lfloorfrac{n}{d} floor} ijsum_{k|gcd(i,j)}mu(k) ]

枚举 (k)

[sum_{d=1}^ndsum_{k=1}^{lfloorfrac{n}{d} floor}mu(k)k^2sum_{i=1}^{lfloorfrac{n}{kd} floor}sum_{j=1}^{lfloorfrac{n}{kd} floor} ij ]

这里可以直接数论分块 (O(n)) 解决。

继续将这个式子变形, 考虑枚举 (T=kd)

[sum_{T=1}^n F(lfloorfrac{n}{T} floor)^2Tsum_{d|T}mu(d)d ]

可以发现后面的 (g(T)=sum_{d|T}mu(d)d) 是一个积性函数,可以线性筛出来。

这样对于单次询问复杂度 (O(sqrt{n}))

Problem 2.

[sum_{i=1}^nsum_{j=1}^md(ij) ]

(d(i))(i) 的约数个数

有一个结论

[d(ij)=sum_{x|i}sum_{y|j}[gcd(x,y)=1] ]

显然每个质因子 (p) 的贡献是独立的,(d(x)) 为每种质因子贡献的乘积,设 (i=i'p^{k_1},j=j'p^{k_2}) 可以发现左边贡献为 (k_1+k_2+1) ,右边贡献为 (k_1+1+k_2+1-1)([gcd(p^{t_1},p^{t_2})=1],t_1leq k_1,t_2leq k_2)),所以得证。

[sum_{i=1}^nsum_{j=1}^msum_{x|i}sum_{y|j}[gcd(x,y)=1]\ sum_{i=1}^nsum_{j=1}^msum_{x|i}sum_{y|j}sum_{d|gcd(x,y)}mu(d) ]

按照套路考虑枚举 (d) ,显然此时 (x,y)(d) 有贡献,仅当 (gcd(x,y))(d) 的倍数。

所以 (x)(d) 的倍数,(y)(d) 的倍数。

[sum_{d=1}^{min(n,m)}sum_{x=1}^{lfloorfrac{n}{d} floor}sum_{y=1}^{lfloorfrac{m}{d} floor}sum_{i=1}^{lfloorfrac{n}{xd} floor}sum_{j=1}^{lfloorfrac{m}{yd} floor}mu(d) ]

考虑设 (f(n))

[f(n)=sum_{x=1}^{n}lfloorfrac{n}{x} floor ]

显然 $f(n) $ 不难发现 (f(n)=sum_{i=1}^n d(i))

考虑线性筛筛出 (d(i))

[sum_{d=1}^{min(n,m)}mu(d)f(lfloorfrac{n}{d} floor)f(lfloorfrac{m}{d} floor) ]

这个显然可以数论分块,总复杂度 $O(n) $

总结

一般来说莫比乌斯反演的题目,主要考虑化为 ([gcd(x,y)=1]) ,通过交换枚举顺序构造积性函数,或者使用数论分块求解,最重要的是抓住运算的性质和熟练掌握反演公式。

Min_25 筛

规定 (P) 是所有质数组成的集合,若无特殊说明 (p) 为质数。

[sum_{i=1}^Nf(i) ]

其中 (f(n)) 为积性函数,并且 (f(p^k)) 能够快速计算,(f(p)) 能够表示为一个简单多项式。

筛质数的答案

首先需要对每个 (n=lfloorfrac{N}{i} floor)求出 (sum_{i=1}^n[iin P]f(i))

首先线性筛出 (sqrt{n}) 以内的所有质数,(P_i) 表示第 (i) 个质数。

因为 (f(p)) 能够写成一个简单多项式

[sum_{i=1}^n [iin P] f(i) = sum_{i=1}^n [iin P] sum_{k=0}^{infty} a_k i^k = sum_{k=0}^{infty} a_k sum_{i=1}^n [iin P] i^k ]

所以本质上来说需要求解的是 (sum_{i=1}^n [iin P] i^k)

考虑构造一个函数 (g(n,j)) 满足

[g(n,j)=sum_{i=1}^{n}[i in P or min(p)>P_j]i^k ]

$min (i) $ 表示 (i) 的最小质因子。

其实不难发现 (g(n,j)) 相当于运行了 (j) 次埃氏筛后,没有被筛掉的数和质数的 (i^k) 的和。

考虑如何求 (g(n,j)) ,发现这个转移可以分类讨论

[g(n,j)=egin{cases} g(n,j-1)&P_j^2gt n\ g(n,j-1)-P_j^k[g(lfloorfrac{n}{P_j} floor,j-1)-g(p_{j-1},j-1)]&P_j^2le nend{cases} ]

考虑第 (j) 次筛质数,显然筛掉的是最小质因子大于 (P_j) 的数,而满足这个条件数必然大于 (P_j^2)

所以如果 (n<P_j^2) ,这次筛是不会筛掉任何数的,显然 (g(n,j)=g(n,j-1))

否则 (ngeq P_j^2) ,显然会筛掉 (P_j) 的所有倍数(最小质因子为 $P_j $)。

不难发现 (i^k) 是一个完全积性函数,可以将需要删掉的 (P_j) 的倍数表示为 (P_jcdot s) ((2leq sleq lfloorfrac{n}{P_j} floor),且 (s) 的最小质因子大于等于 (P_j)),不难发现 (g(lfloorfrac{n}{P_j} floor,j-1)) 为所有合法的 (s^k) 的和加上 (sum_{i=1}^{j-1}P_i^k) ,而 (g(p_{j-1},j-1)) 恰好等于 (sum_{i=1}^{j-1}P_i^k) ,所以 (g(lfloorfrac{n}{P_j} floor,j-1)-g(p_{j-1},j-1)) 就是所有合法的 (s^k) 的和,而 (i^k) 是完全积性函数,只需要乘上 (P_j^k) 就是需要删掉的数。

边界条件 (g(n,0)=sum_{i=1}^n i^k) 显然 (k) 较小的情况可以直接手推公式,(k) 较大可以考虑插值((k) 大了时间复杂度爆炸)。

筛所有数的答案

[S(n,j) = sum_{i=1}^n [min(i) > p_j] f(i) ]

如果分质数与合数讨论显然可以得到

[S(n,j)=g(n,|P|)-g(p_{j},j)+sum_{k=j+1}^{P_k^2leq n}sum_{e=1}^{P_k^{e}le n}f(P_k^e)(S(lfloorfrac{n}{P_k^e} floor,k)+[e ot=1]) ]

前面一部分即为所有质数的贡献,而后面求合数的贡献,非常好理解就是暴力枚举 (P_k) 及其次幂然后求值,要注意的是 (S(lfloorfrac{n}{P_k^e} floor,k+1)f(P_k^e)) 并不包含出 (P_k^{e+1}) 的函数值,所以还需要加上 (f(P_k^{e+1}))

总复杂度 (O(frac{n^{frac{3}{4}}}{log n}))

关于实现方面的细节

有一个性质 (lfloorfrac{lfloorfrac{n}{a} floor}{b} floor=lfloorfrac{n}{ab} floor) 所以我们只需要预处理所有的 (g(lfloorfrac{n}{x} floor,j)) 就可以了。

在这里如果使用 map 储存复杂度显然会变大,考虑到 (lfloorfrac{n}{lfloorfrac{n}{x} floor} floor)(lfloorfrac{n}{x} floor) 中必然有一个数 (leq sqrt{n}) ,所以可以直接用两个数组储存编号。

(S(n,j)) 运算的时候不需要记忆化,因为调用的所有 (S(n,j)) 中没有相同的整数对 ((n,j))

(sum_{i=1}^ni=frac{n(n+1)}{2})

(sum_{i=1}^ni^2=frac{n(n+1)(2n+1)}{6})

(sum_{i=1}^ni^3=frac{n^2(n+1)^2}{4})

(sum_{i=1}^{n}i^4=frac{n(n+1)(2n+1)(3n^2+3n-1)}{30})

举个简单的例子

[f(p^k)=p^k(p^k-1) ]

#include<bits/stdc++.h>
using namespace std;
namespace Min_25
{
	const int mod=1e9+7,inv2=(mod+1)/2,inv3=(mod+1)/3;
	const int maxn=1e6+10;
	int md(int x){return x>=mod?x-mod:x;}
	bool flag[maxn];
	int g1[maxn],g2[maxn];
	long long w[maxn];
	int id1[maxn],id2[maxn],m;
	int sum1[maxn],sum2[maxn],lim;	
	int prime[maxn],cnt=0;
	void make_prime(int n)
	{
		for(int i=2;i<=n;i++)
		{
			if(!flag[i])
			{
				prime[++cnt]=i;
				sum1[cnt]=(sum1[cnt-1]+i);
				sum2[cnt]=(sum2[cnt-1]+i*1LL*i)%mod;
			}
			for(int j=1;j<=cnt&&prime[j]*i<=n;j++)
			{
				flag[prime[j]*i]=1;
				if(i%prime[j]==0)break;
			}
		}
	}
	long long n;
	void G()
	{
		m=0;
		for(long long i=1,j;i<=n;i=j+1)
		{
			w[++m]=n/i,j=n/w[m];
			if(w[m]<=lim)id1[w[m]]=m;
			else id2[n/w[m]]=m;
			int t=w[m]%mod;
			g1[m]=(t+1)*1LL*t/2%mod-1;
			g2[m]=(t+1)*1LL*t/2%mod*(t*2+1)%mod*inv3%mod-1;
		}
		for(int i=1;i<=cnt;i++)
		for(int j=1;j<=m&&prime[i]*1LL*prime[i]<=w[j];j++)
		{
			int lst=w[j]/prime[i]<=lim?id1[w[j]/prime[i]]:id2[n/(w[j]/prime[i])];
			g1[j]=md(g1[j]+mod-(g1[lst]-sum1[i-1]+mod)*1LL*prime[i]%mod);
			g2[j]=md(g2[j]+mod-(g2[lst]-sum2[i-1]+mod)*1LL*prime[i]%mod*prime[i]%mod);
		}
	}
	int S(long long a,int j)
	{
		if(prime[j]>=a)return 0;
		int id=a<=lim?id1[a]:id2[n/a];
		int ans=md(md(g2[id]+mod-g1[id])+mod-md(sum2[j]+mod-sum1[j]));
		for(int k=j+1;prime[k]*1LL*prime[k]<=a&&k<=cnt;k++)
		{
			long long pe=prime[k];
			for(int e=1;pe<=a;e++,pe*=prime[k])
			{
				long long tmp=pe%mod;
				ans=(ans+tmp*(tmp-1)%mod*(S(a/pe,k)+(e!=1)))%mod;
			}
		}
		return ans;
	}	
	int Sum(long long N)
	{
		n=N;
		lim=sqrt(n);
		make_prime(lim);
		G();
		return (S(n,0)+1)%mod;
	}
}
long long n;
int main()
{
	scanf("%lld",&n);
	printf("%d
",Min_25::Sum(n));
}

杜教筛

常见积性函数

  • (mu(x)) 莫比乌斯反演函数。
  • (varphi(x)) 欧拉函数 (varphi(x)=sumlimits_{i=1}^x[gcd(x,i)=1])
  • (d(x)) 约数个数函数 (d(x)=sumlimits_{i=1}^n[i|n])
  • (sigma(x)) 约数个数和函数 (sigma(x)=sumlimits_{i=1}^n[i|n]i)
  • (I(x)) 恒等函数函数值恒为 (1)
  • (epsilon(x)) 元函数 (epsilon(x)=[x=1])
  • (id(x)) 单位函数 (id(x)=x)

狄利克雷卷积

[(f*g)(n)=sum_{d|n}f(d) cdot g(frac{n}{d}) ]

满足交换律,结合律,分配律。

不难发现存在 (f*epsilon=f)

杜教筛

需要计算积性函数 (f(x)) 的前缀和。

[S(n)=sum_{i=1}^n f(i) ]

考虑寻找到两个积性函数使得 (h=g*f) ,那么有

[sum_{i=1}^{n}h(i)=sum_{i=1}^{n}sum_{d|i}g(d)cdot f(frac{i}{d}) =sum_{d=1}^{n}g(d)cdotsum_{i=1}^{lfloorfrac{n}{d} floor}f({i})\ sum_{i=1}^{n}h(i)=sum_{d=1}^{n}g(d)cdot S(lfloorfrac{n}{d} floor) ]

考虑将 (d=1) 对应的项提出来

[sum_{i=1}^{n}h(i)=g(1)cdot S(n)+sum_{d=2}^{n}g(d)cdot S(lfloorfrac{n}{d} floor)\ g(1)S(n)=sum_{i=1}^{n}h(i)-sum_{d=2}^{n}g(d)cdot S(lfloorfrac{n}{d} floor) ]

也就是说只要 (h(x)) 前缀和很好求,那么这个式子就可以使用整除分块完成计算。

例子

  • (mu*I=epsilon)

  • (varphi*I=id)

int smu[maxn];
long long sphi[maxn];
int mu[maxn],phi[maxn];
int prime[maxn],cnt=0,flag[maxn];
void make_prime(int n)
{
	mu[1]=1,phi[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!flag[i])
		{
			prime[++cnt]=i;
			mu[i]=-1,phi[i]=i-1;
		}
		for(int j=1;j<=cnt&&prime[j]*i<=n;j++)
		{
			flag[prime[j]*i]=1;
			if(i%prime[j]==0)
			{
				mu[prime[j]*i]=0;
				phi[prime[j]*i]=phi[i]*prime[j];
				break;
			}
			mu[prime[j]*i]=-mu[i];
			phi[prime[j]*i]=phi[i]*phi[prime[j]];
		}
	}
	for(int i=1;i<=n;i++)smu[i]=smu[i-1]+mu[i],sphi[i]=sphi[i-1]+phi[i];
}
unordered_map<long long,long long>phimp;
unordered_map<long long,int>mump;
long long Sphi(long long n)
{
	if(n<=5e6)return sphi[n];
	if(phimp.count(n))return phimp[n];
	long long ans=n*(n+1)/2;
	for(long long i=2,j;i<=n;i=j+1)
	{
		j=n/(n/i);
		ans-=(j-i+1)*Sphi(n/i);
	}
	return phimp[n]=ans;
}
int Smu(long long n)
{
	if(n<=5e6)return smu[n];
	if(mump.count(n))return mump[n];
	int ans=1;
	for(long long i=2,j;i<=n;i=j+1)
	{
		j=n/(n/i);
		ans-=(j-i+1)*Smu(n/i);
	}
	return mump[n]=ans;
}
原文地址:https://www.cnblogs.com/Harry-bh/p/12394999.html