数论(min_25筛)

类欧几里得算法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
扩展欧拉定理(对于a,p不互质的情况计算a%p):https://blog.csdn.net/hzj1054689699/article/details/80693756

二次剩余

https://blog.csdn.net/kele52he/article/details/78897187
对于n整数a若存在整数x 满足 x^2%n=a那么称a是mod n 的二次剩余
判定:当且仅当 a^(p-1)/2=1
引理:对于奇素数p下的二次剩余n,有两个不同的x满足x^2%p=n
一个奇素数的完全剩余系下有(p-1)/2 个二次剩余。

Cipolla 算法

求解 x^2=n mod p, O ( n log ⁡ n ) O(n\log n) O(nlogn)

步骤:
1.随机一个 a,使得 ( a 2 − n ) ( p − 1 ) / 2 = − 1 m o d    p (a^2-n)^{(p-1)/2}=-1\mod p (a2n)(p1)/2=1modp,期望次数 2 次。
2.令 ω = a 2 − n \omega=\sqrt{a^2-n} ω=a2n ,扩域为虚根。
3. ( a + ω ) ( p + 1 ) / 2 (a+\omega)^{(p+1)/2} (a+ω)(p+1)/2 即为所求。

//xy%p=xy-(xy)/p*p
inline ll qmul(ll a,ll b,ll mod)
{
    a%=mod,b%=mod;
    return (((a*b)-(ll)((ll)((long double)a/mod*b+1e-3)*mod))%mod+mod)%mod;
}

扩展BSGS

在这里插入图片描述

狄利克雷卷积的逆

f ∗ f − 1 = e f*f^{-1}=e ff1=e。通过构造,可以 O ( n log ⁡ n ) O(n\log n) O(nlogn) 构造出函数的逆。
如果积性函数 f f f g g g 对于任意质数 p p p 满足 f ( p ) = g ( p ) = 1 f(p)=g(p)=1 f(p)=g(p)=1,我们就可以快速求出 f f f 的前缀和。
h = f ∗ g − 1 h=f*g^{-1} h=fg1,那么就有 f ( p ) = g ( 1 ) h ( p ) + g ( p ) h ( 1 ) = h ( p ) + 1 = 1 f(p)=g(1)h(p)+g(p)h(1)=h(p)+1=1 f(p)=g(1)h(p)+g(p)h(1)=h(p)+1=1,推出 h ( p ) = 0 h(p)=0 h(p)=0
我们要求的是:
∑ i = 1 n f ( i ) = ∑ i = 1 n ∑ d ∣ i g ( d ) h ( i d ) = ∑ d = 1 n h ( d ) ∑ i = 1 n / d g ( i ) \sum_{i=1}^n f(i) = \sum_{i=1}^n\sum_{d|i}g(d)h(\frac i d) = \sum_{d=1}^nh(d)\sum_{i=1}^{n/d} g(i) i=1nf(i)=i=1ndig(d)h(di)=d=1nh(d)i=1n/dg(i)
由于 h h h 只在所有质因子次数都大于 1 的情况下才不为零,这样的数可以写成 a 2 b 3 a^2b^3 a2b3 的形式,不超过 O ( n ) O(\sqrt n) O(n ) 个。枚举 a a a,枚举 b b b,就得到了 a 2 b 3 a^2b^3 a2b3 的质因数分解,即可快速计算。

狄利克雷生成函数

F ( s ) = ∑ i = 0 ∞ f ( i ) / i s F(s)=\sum_{i=0}^{\infin}f(i)/i^s F(s)=i=0f(i)/is
多项式卷积即为狄利克雷卷积。

定义求导算子 ′ ' :当 p p p 为质数时, p ′ = 1 p'=1 p=1,对于整数 a a a b b b,有 ( a b ) ′ = a ′ b + a b ′ (ab)'=a'b+ab' (ab)=ab+ab

1

∑ i = 1 n gcd ⁡ ( i , i ′ ) \sum_{i=1}^n \gcd(i,i') i=1ngcd(i,i)
??? ??? ???

min_25 筛

作用:计算积性函数前缀和。复杂度 O ( n 3 / 4 log ⁡ n ) O(\frac{n^{3/4}}{\log n}) O(lognn3/4)
要求: f ( p ) f(p) f(p) 为关于 p p p 的低次多项式, f ( p c ) f(p^c) f(pc) 能很快计算。

第一步

首先我们想要求所有质数的函数值。构造完全积性函数 F ( n ) F(n) F(n),满足 F ( p ) = f ( p ) F(p) = f(p) F(p)=f(p)。记 g ( n , j ) = ∑ i = 1 n [ m i n d ( i ) > p j ]   F ( i ) g(n,j)=\sum_{i=1}^n [mind(i)>p_j]~F(i) g(n,j)=i=1n[mind(i)>pj] F(i) m i n d ( i ) mind(i) mind(i) 表示 i i i 的最小质因子。换句话说统计的是质数和最小值因子大于 p j p_j pj 的数的贡献。我们的目的便是求 g ( n , ∣ P ∣ ) g(n, |P|) g(n,P)

构造完全积性函数的目的一是使 g ( n , 0 ) g(n, 0) g(n,0) 好算。比如如果 f ( p ) f(p) f(p) 是低次单项式,那么 g ( n , 0 ) g(n, 0) g(n,0) 就是自然数幂和;如果 f ( p ) f(p) f(p) 是低次多项式,因为我们是求和,因此可以拆成若干个单项式再相加,转化为上一种情况。

初始,我们知道 g ( n , 0 ) g(n,0) g(n,0) 的值,考虑用质数把合数的贡献筛掉。构造完全积性函数的目的之二就是方便我们能够筛掉合数的贡献。我们按照 j j j 从小到大的顺序转移 g g g。考虑 g ( n , j − 1 ) g(n,j-1) g(n,j1) 转移到 g ( n , j ) g(n,j) g(n,j),有哪些数变得不合法了。就是那些最小质因子刚好为 p j p_j pj 的那些数。

注意到,如果 p j 2 p_j^2 pj2 如果大于 x x x,由于没有小于 x x x 的合数含有 p j p_j pj,因此直接转移过来。
g ( n , j ) = { g ( n , j − 1 ) − p j k ( g ( n / p j , j − 1 ) − g ( p j − 1 , j − 1 ) ) , p j 2 ≤ n g ( n , j − 1 ) , p j 2 > n g(n,j)= \begin{cases} g(n,j-1)-p_j^k\big(g(n/p_j,j-1)-g(p_j-1,j-1)\big)&,p_j^2\leq n\\ g(n,j-1)&,p_j^2>n \end{cases} g(n,j)={g(n,j1)pjk(g(n/pj,j1)g(pj1,j1))g(n,j1)pj2npj2>n
第一维只有根号 n n n 大小。发现求 g g g 的过程与原函数是不是积性函数没关系( F ( x ) F(x) F(x) 是我们构造的),因此可以求 1 1 1 n n n 质数个数。

第二步

考虑用这个东西求函数的前缀和。定义 s ( n , j ) = ∑ i = 1 n [ m i n d ( i ) ≥ p j ]   f ( i ) s(n,j)=\sum_{i=1}^n[mind(i)\geq p_j]~f(i) s(n,j)=i=1n[mind(i)pj] f(i)。目标是求 s ( n , 1 ) s(n,1) s(n,1),边界条件是 s ( n , ∣ p ∣ ) s(n,|p|) s(n,p) 为所有质数的答案。因此我们递归计算 s s s。转移的时候枚举最小质因子,枚举最小质因子 p k p_k pk 的次数 e e e s [ n / p k e ] [ k + 1 ] s[n/p_k^e][k+1] s[n/pke][k+1]。注意单独考虑 f ( p k e ) f(p_k^e) f(pke)

s ( n , j ) = g ( n , ∣ p ∣ ) − ∑ i = 1 j − 1 f ( p i ) + ∑ k ≥ j ∑ e ( f ( p k e ) s ( n / p k e , k + 1 ) + f ( p k e + 1 ) ) s(n,j)=g(n,|p|)-\sum_{i=1}^{j-1}f(p_i)+\sum_{k\geq j}\sum_e\big(f(p_k^e)s(n/p_k^e,k+1)+f(p_k^{e+1}) \big) s(n,j)=g(n,p)i=1j1f(pi)+kje(f(pke)s(n/pke,k+1)+f(pke+1))

Loj6053 简单的函数
Notice: 1 拿出来最后单独统计,val 数组里的值从大到小,数组开到两倍根号。

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define ld long double
using namespace std;
const int mod=1e9+7,M=200010,inv2=(mod+1)/2;
int ind1[M],ind2[M];
bool np[M];
ll sum[M],p[M],cnt,tot,h[M],g[M],val[M],n,B;
int read()
{
	int x=0;char c=getchar(),flag='+';
	while(!isdigit(c)) flag=c,c=getchar();
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
	return flag=='-'?-x:x;
}
void init(int n)
{
	np[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!np[i]) p[++cnt]=i;
		for(int j=1;j<=cnt&&i*p[j]<=n;j++) 
		{
			np[i*p[j]]=1;
			if(i%p[j]==0) break;
		}
	}
	for(int i=1;i<=cnt;i++) sum[i]=(sum[i-1]+p[i])%mod;
}
ll S(ll x,int j)
{
	if(x<=1||x<p[j]) return 0;
	int t=(x<=B)?ind1[x]:ind2[n/x];
	ll ans=g[t]-sum[j-1]-h[t]+(j-1);
	if(j==1) ans+=2;
	for(int k=j;k<=cnt&&p[k]*p[k]<=x;k++)
	{
		ll t1=p[k],t2=p[k]*p[k];
		for(int e=1;t2<=x;e++,t1=t2,t2*=p[k])
			ans=(ans+(p[k]^e)*S(x/t1,k+1)+(p[k]^(e+1)))%mod;
	}
	return ans;
}
int main()
{
	cin>>n;
	init(B=sqrt(n)+1);
	for(ll l=1,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		val[++tot]=n/l;
		if(n/l<=B) ind1[n/l]=tot;
		else ind2[r]=tot;
		ll t=(n/l)%mod;
		h[tot]=(t-1)%mod;
		g[tot]=(2+t)*(t-1)%mod*inv2%mod;
	}
	for(int j=1;j<=cnt;j++)
	{
		for(int i=1;i<=tot&&p[j]*p[j]<=val[i];i++)
		{
			int t=(val[i]/p[j]<=B)?ind1[val[i]/p[j]]:ind2[n/(val[i]/p[j])];
			g[i]=(g[i]-p[j]*(g[t]-sum[j-1]))%mod;
			h[i]=(h[i]-h[t]+j-1)%mod; 
		}
	}
	cout<<(S(n,1)%mod+1+mod)%mod;
	return 0;
}
/*by DT_Kang*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值