数学小专题
正文
简单复习一下数学的几个模板。
总感觉数学还是要多复习,不然很容易忘记。
简单数论
判定质数
不用多讲。
Miller-Rabin算法
bool mr(ll x,ll b)
{
if(qp(b,x-1,x)!=1)
return false;
ll k=x-1;
while((k&1)==0)
{
k>>=1;
ll d=qp(b,k,x);//快速幂,计算b^k mod x
if(d!=1 && d!=x-1)
return false;
if(d==x-1)
return true;
}
return true;
}
bool mr(ll x)
{
if(x==46856248255981)
return false;
if(x==2||x==3||x==7||x==61||x==24251)
return true;
return mr(x,2)&&mr(x,3)&&mr(x,7)&&mr(x,61)&&mr(x,24251);
}
对于一个数
- 在第一次计算时不考虑
的情况。 - 遇到
或者 为奇数的情况就直接判定正确。
注意
约数 筛法
又叫试除法。每次围绕
倍数法
和线性筛的代码比较类似,适合一次筛多个质数的问题。
gcd
埃式筛
比较好理解。
线性筛
for(rg int i = 1; i <= N; ++ i)
{
if(v[i] < 0)
{
v[i] = i;
prime[++ pn] = i;
}
for(rg int j = 1; j <= pn; ++ j)
{
if(prime[j] * i > N || prime[j] > v[i])
break;
v[i * prime[j]] = prime[j];
}
}
暂时还没有试过这个代码。从理论上来说应该是没错的。
进阶数论
冷知识
设一个数的分解式:
我们可以把指数提取出来:
它可以帮助我们从全新的角度观察数论。其实说白了就是把数论中的运算变成对数形式。
举个例子,求两个数的
这样我们就可以把方程
再举个例子,整除关系:
这样就也把整除关系变成若干个不等式了。从本质上来说,
可以结合这道题看一下:CSP-S 2009 Hankson的趣味题
重要函数的计算与预处理
欧拉函数
int phi(int n)
{
int ret = n;
for(rg int i = 2; i * i <= n; ++ i)
if(n % i == 0)
{
ret = ret / i * (i - 1);
while(n % i == 0)
n /= i;
}
if(n > 1)
ret = ret / n * (n - 1);//n是质数
return ret;
}
这个是直接根据定义式计算的。
它的预处理版本:
void init()
{
for(rg int i = 2; i <= n; ++ i)
phi[i] = i;
for(rg int i = 2; i <= n; ++ i)
if(phi[i] == i)
for(int j = i; j <= n; j += i)
phi[j] = phi[j] / i * (i - 1);
}
当然,还有基于线性筛的版本:
void init()
{
for(rg int i = 2; i <= N; ++ i)
{
if(v[i] == 0)
{v[i] = i, prime[++ pn] = i, phi[i] = i - 1;}
for(rg int j = 1; j <= pn; ++ j)
{
if(prime[j] * i > N || prime[j] > v[i])
break;
v[i * prime[j]] = prime[j];
phi[i * prime[j]] = phi[i] * (i % prime[j] == 0 ? prime[j] : prime[j] - 1);
}
}
}
这里用到了
莫比乌斯函数
for(rg int i = 1; i <= N; ++ i)
mu[i] = 1, v[i] = 0;
for(rg int i = 2; i <= N; ++ i)
{
if(v[i])
continue;
mu[i] = -1;
for(rg int j = (i << 1); j <= N; j += i)
{
v[j] = 1;
if((j / i) % i == 0)
mu[j] = 0;
else
mu[j] *= -1;
}
}
顺带一提,学长zsy讲过一个非常有趣的理解方式。这里不妨粘贴之。
我们都知道莫比乌斯反演:(简便起见,这里直接写成卷积形式)
从之前的素因子式
实际上,我之前补充过一个冷知识:广义的莫比乌斯反演。对于偏序关系
则有:
这实际上说明了莫比乌斯反演实质上就是一个局部有限偏序集上的高维前缀和差分变换。这也进一步说明了莫比乌斯函数在容斥原理和数论上的链接作用。
模算术
正如你所见,
欧拉定理
若正整数
对于任意正整数
如果
证明均略去。
裴蜀定理和exgcd
对于整数方程
它的证明是基于
根据数学归纳法,假设下面这个方程成立:
根据模数的另一种定义:
我们可以得到:
整理得到:
因此,我们令
在程序中可以这样简写:
inline ll exgcd(ll a, ll b, ll &x, ll &y)
{
if(b == 0)
{
x = 1, y = 0;
return a;
}
ll d = exgcd(b, a % b, y, x);
y -= (a / b) * x;
return d;
}
一次同余方程FCE
一般形式为
假设
注意一下得到特解
逆元
值得注意的是逆元的几种非常特殊的求法:
-
如果
是质数,那么 的逆元就是 。 -
线性求逆元:
-
线性求阶乘逆元:
稍微注意一下,在用阶乘求逆元时可能会出现
中国剩余定理
设方程组:
当
其中
假设
设
已知
另外有个小技巧:求乘积
int main()
{
n=qr(1);
RP(i,1,n)
m[i]=qr(1ll),a[i]=qr(1ll);//x = a[i] (mod m[i])
ans=0,M=1;//M = prod
RP(i,1,n)
{
ll p=FCE(M,a[i]-ans,m[i]);
ans=ans+p*M;
M*=m[i]/gcd(M,m[i]);
ans=((ans%M)+M)%M;
}
printf("%lld",((ans%M)+M)%M);
return 0;
}
高次同余方程(指数型)
求解形如
这里没有一般的解析方法。但是由于
设
方程变成了:
即:
对于所有的
这种方法叫做Baby step,Giant step。是一种类分块的优化枚举。
简单的线性代数
矩阵可以看成一个二维数表,可以用两个紧挨的下标
矩阵加法就是对应的元素相加,即:
矩阵乘法相对复杂。只有形如
可以理解为:
矩阵乘法的应用
对于一个
由于是线性递推关系,我们可以把所有的状态
此时这个
又叫作转移矩阵。
如果知道这个递推关系,想要从
如果上面不是齐次递推关系,而是带了一个常数
当然,直接代入矩阵乘法的公式,对着公式依次赋值,才是最稳妥的做法。
当然,矩阵乘法的应用不止于此。考虑这样一个问题:
给定一个带边权无向连通图,求过
个点(不算起点),从 走到 的最短路?
设邻接矩阵
因此最终的答案就是
高斯消元
为节省空间,这里直接接一个链接过去。
线性基
狭义的线性基仅指异或空间下的线性基。其将大小为
线性基可以看成数表
当你想新插入一个数
举个例子。这个线性基:
就是一个不错的线性基。而:
则非常糟糕。最高位为
粘贴一下核心代码:
void bits(ll x)
{
DRP(i,62,0)
{
if(!(x >> (ll)i))
continue;
if(!p[i])
{p[i] = x; break;}
x ^= p[i];
}
}
int main()
{
scanf("%d", &n);
RP(i,1,n)
scanf("%lld", &a[i]), bits(a[i]);
DRP(i,62,0)
if((ans ^ p[i]) > ans)
ans ^= p[i];
cout<<ans;
return 0;
}
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· ThreeJs-16智慧城市项目(重磅以及未来发展ai)
· .NET 原生驾驭 AI 新基建实战系列(一):向量数据库的应用与畅想
· Ai满嘴顺口溜,想考研?浪费我几个小时
· Browser-use 详细介绍&使用文档
· 软件产品开发中常见的10个问题及处理方法