数学
基础数学
二元一次方程组 { a 11 x + a 12 y = b 1 a 21 x + a 22 y = b 2 的解 \text { 二元一次方程组 }\left\{\begin{array}{l} a_{11} x+a_{12} y=b_{1} \\ a_{21} x+a_{22} y=b_{2} \end{array}\right. \text { 的解 } 二元一次方程组 {a11x+a12y=b1a21x+a22y=b2 的解
$$
x=\frac{\left|\begin{array}{ll}
b_{1} & a_{12} \
b_{2} & a_{22}
\end{array}\right|}{\left|\begin{array}{ll}
a_{11} & a_{12} \
a_{21} & a_{22}
\end{array}\right|}
y=\frac{\left|\begin{array}{ll}
a_{11} & b_{1}\
a_{21} & b_{2}
\end{array}\right|}{\left|\begin{array}{ll}
a_{11} & a_{12} \
a_{21} & a_{22}
\end{array}\right|}
$$
对数
某些浮点数精度问题可用对数转换
log
a
(
M
⋅
N
)
=
log
a
M
+
log
a
N
\log _{a}(M \cdot N)=\log _{a} M+\log _{a} N
loga(M⋅N)=logaM+logaN
log a M N = log a M − log a N \log _{a} \frac{M}{N}=\log _{a} M-\log _{a} N logaNM=logaM−logaN
log a b = log c b log c a \log _{a} b=\frac{\log _{c} b}{\log _{c} a} logab=logcalogcb
数列
平方数列
∑
i
=
1
n
x
i
2
=
1
2
+
2
2
+
3
2
+
.
.
.
+
n
2
=
n
3
3
+
n
2
2
+
n
6
=
n
(
n
+
1
)
(
2
n
+
1
)
6
\sum_{i=1}^{n}x^2_i=1^2+2^2+3^2+...+n^2=\frac{n^3}{3}+\frac{n^2}{2}+\frac{n}{6}=\frac{n(n+1)(2n+1)}{6}
i=1∑nxi2=12+22+32+...+n2=3n3+2n2+6n=6n(n+1)(2n+1)
等差数列
S
n
=
n
×
a
1
+
n
×
(
n
−
1
)
2
×
d
S_{n}=n \times a_{1}+\frac{n \times(n-1)}{2} \times d
Sn=n×a1+2n×(n−1)×d
等比数列
S
n
=
n
×
a
1
+
n
×
(
n
−
1
)
2
×
d
S
n
=
{
n
a
1
(
q
=
1
)
a
1
(
1
−
q
n
)
1
−
q
=
a
1
−
a
n
q
1
−
q
(
q
≠
1
)
S_{n}=n \times a_{1}+\frac{n \times(n-1)}{2} \times dS n=\left\{\begin{array}{l} n a_{1}(q=1) \\ \frac{a_{1}\left(1-q^{n}\right)}{1-q}=\frac{a_{1}-a_{n} q}{1-q}(q \neq 1) \end{array}\right.
Sn=n×a1+2n×(n−1)×dSn={na1(q=1)1−qa1(1−qn)=1−qa1−anq(q=1)
最大公因数
__gcd(int x,int y);
ex_gcd
求解
x0*a + y0*b==gcd( a,b )
的一个解返回值是
gcd(a,b)
通解 :
X = x0+b/gcd(a , b) * t
Y = y0+a/gcd(a , b) * t
再次扩展 : :
x*a + y*b==c
有解 若c%gcd(a,b)==0
则有解,否者无解设
a*x0+b*y0==gcd(a , b)
则
x = x0*c/gcd(a , b)
则
y = y0*c/gcd(a , b)
通解 :
X = x0*c/gcd(a,b) + b/gcd(a,b)*t
Y = y0*c/gcd(a,b) - a/gcd(a,b)*t
最小整数解 : x = (x % tem + tem) % tem
其中tem = b/gcd(a,b)
ll ex_gcd(ll a,ll b,ll &x,ll &y){
if( b==0 ){
x = 1;
y = 0;
return a;
}
ll d=ex_gcd(b,a%b,x,y);
ll tem = x;
x = y;
y = tem - a / b * y;
return d;
}
ll a,b,c,x,y;
int main(){
cin>>a>>b>>c;
ll GG=ex_gcd(a,b,x,y);
x=x*c/GG;
y=y*c/GG;
repi(i,0,5){//输出通解
cout<<"("<<a<<") * ("<<x<<") + ("<<b<<") * ("<<y<<") = "<<c<<endl;
x+=b/GG;
y-=a/GG;
}
return 0;
}
最小公倍数
(a,b的最小公倍数)*(a,b的最大公因数)=a*b;
素数
埃式筛
bool pri[10000005];
void prime(int x){
int i,j,k; //毕竟int需要时间
for(i=2;i*i<=x;i++){
if(!pri[i]){
k=x/i;
for(j=i;j<=k;j++)
if(!pri[j*i]) //经测试比直接赋值pri[i*j]=1快
pri[j*i]=1;
}
}
}
欧拉筛(线性筛)
论如何优雅地跑过1e8,大概需要也0.7s,泪目
int zis[6000005],pri_size;//1e8时开6e6够了
bool pri[100000005];
void prime(int x){
for(int i=2;i<=x;i++){
if(!pri[i]) zis[pri_size++]=i;
for(int j=0;zis[j]*i<=x;j++){
pri[zis[j]*i]=1;
if(i%zis[j]==0) break;
}
}
}
约数
vector<ll> get_divisors(ll x){
vector<ll> res;
for (ll i = 1; i <= x / i; i ++ )
if (x % i == 0){
res.push_back(i);
if (i != x / i) res.push_back(x / i);
}
sort(res.begin(), res.end());
return res;
}
欧拉函数
求单个欧拉函数
欧拉函数表示的是小于等于
n
和n互质的数的个数
n
为素数是欧拉值为n-1
欧拉值为n的最小数是大于n的第一个素数
ll euler_phi(ll n){
ll ans = n;
for (ll i = 2; i * i <= n; i++)
if (n % i == 0) {
ans = ans / i * (i - 1);
while (n % i == 0) n /= i;
}
if (n > 1) ans = ans / n * (n - 1);
return ans;
}
线性欧拉函数筛
优雅跑过2e7
int phi[maxn];///欧拉函数
int zis[maxn],cnt=0;///素数
bool vis[maxn];
void euler(int x){
phi[1]=1;
for(int i=2;i<=x;i++)
{
if(!vis[i]) zis[++cnt]=i,phi[i]=i-1;///素数情况
for(int j=1;j<=cnt&&i*zis[j]<=x;j++){
vis[i*zis[j]]=1;///素数倍数非素数
if(i%zis[j]){
phi[i*zis[j]]=phi[i]*(zis[j]-1);
}else{
phi[i*zis[j]]=phi[i]*zis[j];
break;
}
}
// printf("phi(%d)=%lld\n",i,phi[i]);
}
}
快速加法
long long q_mul( long long a, long long b, long long mod ) //快速计算 (a*b) % mod
{
long long ans = 0; // 初始化
while(b) //根据b的每一位看加不加当前a
{
if(b & 1) //如果当前位为1
{
b--;
ans =(ans+ a)%mod; //ans+=a
}
b /= 2; //b向前移位
a = (a + a) % mod; //更新a
}
return ans;
}
快速幂||取余运算
inline ll fpow(ll ba,ll po){
ll res=1; ba%=mod;
while(po>0){
if(po & 1) res=(res*ba)%mod;
ba=(ba*ba)%mod;
po>>=1;
}
return res%mod;
}
矩阵快速幂
const int NN=4;
struct Matrix{
ll a[NN+1][NN+1];
void inta_1(){
memset( a,0,sizeof(a) );
for(int i=1;i<=NN;i++) a[i][i]=1;
}
};
Matrix mul_Matrix( Matrix &a,Matrix &b ){
Matrix res;
memset( res.a,0,sizeof(res.a) );
for(int i=1;i<=NN;i++){
for(int j=1;j<=NN;j++){
for(int k=1;k<=NN;k++){
res.a[i][j]+=a.a[i][k]*b.a[k][j]%mod;
res.a[i][j]%=mod;
}
}
}
return res;
}
inline Matrix mpow(Matrix ba,ll po){
Matrix res;
res.inta_1();
while(po>0){
if(po & 1){
res=mul_Matrix(res,ba);
}
ba=mul_Matrix(ba,ba);
po>>=1;
}
return res;
}
高斯消元
浮点型
double a[105][105];
const double eps=1e-9;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n+1;j++){
cin>>a[i][j];
}
}
for(int j=1;j<=n;j++){
int i;
for(i=j;i<=n;i++) if( fabs(a[i][j])>=eps ) break;
if( fabs(a[i][j])<eps ){
puts("No Solution");
return 0;
}
for(int k=1;k<=n+1;k++) swap(a[i][k],a[j][k]);
for(int k=n+1;k>=j;k--) a[j][k]/=a[j][j];
for(int i=1;i<=n+1;i++){
if(i==j) continue;
for(int k=n+1;k>=j;k--)
a[i][k]-=a[j][k]*a[i][j];
}
}
for(int i=1;i<=n;i++){
printf("%.12f\n",a[i][n+1]);
}
return 0;
}
常见数学结论
gcd(a,b) == 1 == gcd(a+b,a*b)
除数
(1)
如果一个数各个数字相加和为3的倍数,那么这个数是3的倍数
如果一个数各个数字相加和为9的倍数,那么这个数是9的倍数
(2)
如果一个数的 (奇数数字之和 与 偶数数字之和) 之差能被11整除,那么这个数是11的倍数
如果一个数(4位及以上)的后3位数以前与后三位的数字能整除11或7,那么这个数字就是11或7的倍数{
例如:9977后3位以前为9,后3位为977,他们的差为-968,可以被11整除,那么9977就可以被11整除(7同理)
}
(3)
如果
a%b==0
;其中a是一个非常大的数
a=abs(a)
b=abs(b)
那么
ans=(ans*10+a[i]-'0')%b
,ans==0
余数
如果a%nb%n , 则(a-b)%n0
约数
任意一个正整数X都可以表示成若干个质数乘积的形式,即(X=P1^a1) * (P2^a2) …* (Pk^ak)
约数个数=(a1+1)(a2+1)…(ak+1)所有约数和 : ( p1^0 + p1^1 + p1^2 +…+p1^a1 )*…*( pk^0 + pk^1 + pk^2 +…+pk^ak) , 有点像排列组合
斐蜀定理(贝祖定理)
a*X + b*y = c 注 : a , b , c 是整数
若c % ( gcd(a,b) )==0,则这个方程有整数解
对于不定方程 : a1*x1 + a2*x2 + a3*x3 + …+an* xn=c
若c % ( gcd(a1, a2, a3,…,an) )==0,则这个方程有整数解
哥德巴赫猜想
任何一个大于2的偶数都可以表示为两个质数的和
n阶乘末尾0的数目
ll sum(ll n){
ll ans=0;
while(n){
ans+=n/5;
n=n/5;
}
return ans;
}
整除分块数论分块
int sum=0;
for(int i=1;i<=n;i++){
sum+=n/i;
}
对于面结果,我们可以用整除分块来处理
for(int L = 1,R;L<= n; L = R + 1){
r = n / (n / l);//向下取整
sum += n / l * (r - l + 1);
}
//如果遇到向上取整,我们那么r = (n-1)/( (n+L-1)/L - 1 )
排列组合
ll fac[N],ifac[N];
inline ll fpow(ll ba,ll po){
ll res=1; ba%=mod;
while(po>0){
if(po & 1) res=(res*ba)%mod;
ba=(ba*ba)%mod;
po>>=1;
}
return res%mod;
}
inline ll C( ll m,ll n ){
return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
inline ll A( ll m,ll n ){
return fac[n]*ifac[n-m]%mod;
}
inline void init(int len){
fac[0]=ifac[0]=1;
for(ll i=1;i<=len;++i){
fac[i]=fac[i-1]*i%mod;
}
ifac[len]=fpow(fac[len],mod-2);
for(ll i=len-1;i>=1;--i){
ifac[i]=ifac[i+1]*(i+1)%mod;
}
}
结论
上面:m,下面:n
C(m,n) = n! / ( m! * (n-m)!)
C(m,n+1) = C(m,n) + C(m-1,n)
A( m,n ) = n! / (n-m)!
A(m,n) = C(m,n) * A(m,m)
A(m,n) = n*A(m-1,n-1)
C(0,n)+C(1,n)+...C(n,n)=2^n
A(m,n)=mA(m-1,n-1)+A(m,n-1)
C(0,n)+C(2,n)+C(4,n)+...=C(1,n)+C(3,n)+C(5,n)+...=2^(n-1)
C(m,n)为奇数时有n&m=n
组合排列模型
不全相异排列
若在n个元素中 , 有n1个元素彼此相同,n2个元素彼此相同,…且n1+n2+…=r
A
(
n
,
r
)
(
n
1
!
×
n
2
!
×
⋯
×
n
m
!
)
\frac{A(n, r)}{\left(n_{1} ! \times n_{2} ! \times \cdots \times n_{m} !\right)}
(n1!×n2!×⋯×nm!)A(n,r)
圆排列
从n个不同元素中选取m个元素,不分首尾地围成一个圆圈的排列叫做圆排列,其排列方案数为
P
n
m
m
=
n
!
(
n
−
m
)
!
×
m
(
1
≤
m
≤
n
)
\frac{P_{n}^{m}}{m}=\frac{n !}{(n-m) ! \times m}(1 \leq m \leq n)
mPnm=(n−m)!×mn!(1≤m≤n)
错位排列
定义 : 设{ a1,a2,a3,a4,…,an }的一个全排列 , 若对任意的1<=i<=n 都有ai!=i ,则称错位排列
错排公式:
f
[
0
]
=
1
,
f
[
1
]
=
0
,
f
[
2
]
=
1
f
[
n
]
=
(
n
−
1
)
∗
(
f
[
n
−
1
]
+
f
[
n
−
2
]
)
\begin{array}{l} f[0]=1, f[1]=0, f[2]=1 \\ f[n]=(n-1) *(f[n-1]+f[n-2]) \end{array}
f[0]=1,f[1]=0,f[2]=1f[n]=(n−1)∗(f[n−1]+f[n−2])
可重复组合数
从n个不同的元素中,无序的选出r个元素组成一个组合,且允许这r个元素可以重复使用,则称这样的组合为可重复组合 , 其组合数记为 :
H
n
r
=
C
n
+
r
−
1
r
=
n
+
r
−
1
r
!
(
n
−
1
)
!
H_{n}^{r}=C_{n+r-1}^{r}=\frac{n+r-1}{r !(n-1) !}
Hnr=Cn+r−1r=r!(n−1)!n+r−1
不相邻组合数
从A={ 1,2,3,…n }中选取m个不相邻的组合 , 其组合数为 :
C
n
−
m
+
1
m
C_{n-m+1}^{m}
Cn−m+1m
卡特兰数
前几项 : 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452 ,…
f
(
n
)
=
C
2
n
m
n
+
1
f(n)=\frac{C_{2 n}^{m}}{n+1}
f(n)=n+1C2nm
f ( n ) = ∑ i = 0 n − 1 f ( i ) × f ( n − i − 1 ) f(n)=\sum_{i=0}^{n-1} f(i) \times f(n-i-1) f(n)=i=0∑n−1f(i)×f(n−i−1)
f ( n ) = C 2 n n − C 2 n n − 1 f(n)=C_{2 n}^{n}-C_{2 n}^{n-1} f(n)=C2nn−C2nn−1
卡特兰数的应用 :
二叉树的计数 : 已知二叉树有n个结点,求能构成多少种不同的二叉树.
括号化问题 : 一个合法的表达式由 () 包围,() 可以嵌套和连接,如:(())() 也是合法表达式 ,现给出 n 对括号,求可以组成的合法表达式的个数。
划分问题: 将一个凸 n + 2 n+2n+2 多边形区域分成三角形区域的方法数。
出栈问题 : 一个栈的进栈序列为 1 , 2 , 3 , . . n求不同的出栈序列有多少种。
路径问题: 在 n × n 的方格地图中,从一个角到另外一个角,求不跨越对角线的路径数有多少种。
握手问题: 2n 个人均匀坐在一个圆桌边上,某个时刻所有人同时与另一个人握手,要求手之间不能交叉,求共有多少种握手方法。
球盒模型
球相同 盒不同 无空箱
(1)ans
=
C
(
n
−
1
,
m
−
1
)
(
n
>
=
m
)
(2) ans
=
0
(
n
<
m
)
\begin{array}{c} \text { (1)ans }=C(n-1, m-1)(n>=m) \\ \text { (2) ans }=0(n<m) \end{array}
(1)ans =C(n−1,m−1)(n>=m) (2) ans =0(n<m)
可以用插板法,n 个球中总共有 n-1 个空隙,根据条件,我们只需要在 n−1 个空隙中插 m-1 个板子即可。
球相同 盒不同 允许空箱
ans
=
C
(
n
+
m
−
1
,
m
−
1
)
\text { ans }=C(n+m-1, m-1)
ans =C(n+m−1,m−1)
既然允许有空盒,那么我们可以多加 m 个“虚”的球,预先塞进每个盒子。
这样问题就化归成了有 n+m 个相同的球和 m 个不同的盒子,不允许有空盒的情况,直接运用上面的结论就可以解决问题了。
球不同 盒相同 无空箱
即第二类斯特林数
(1)
d
p
[
n
]
[
m
]
=
m
∗
d
p
[
n
−
1
]
[
m
]
+
d
p
[
n
−
1
]
[
m
−
1
]
(
1
<
=
m
<
n
)
d
p
[
k
]
[
k
]
=
1
(
k
>
=
0
)
d
p
[
k
]
[
0
]
=
0
(
k
>
=
1
)
(2)ans
=
0
(
n
<
m
)
\begin{array}{l} \text { (1) } d p[n][m]=m * d p[n-1][m]+d p[n-1][m-1](1<=m<n)\\ d p[k][k]=1(k>=0)\\ d p[k][0]=0(k>=1)\\ \text { (2)ans }=0(n<m) \end{array}
(1) dp[n][m]=m∗dp[n−1][m]+dp[n−1][m−1](1<=m<n)dp[k][k]=1(k>=0)dp[k][0]=0(k>=1) (2)ans =0(n<m)
对于第 n 个球,如果之前的 n-1 个球已经放在了 m 个盒子里,那么第 n 个球就可以随便放在这 m 个盒子中,因为我没有新开一个盒子,那么答案就是m×dp[n-1,m]。
另外,如果我是新开了一个盒子,那么只有一种可能,答案是 dp[n-1][m-1]。
球不同 盒相同 允许空箱
a
n
s
=
∑
d
p
[
n
]
[
i
]
,
0
<
=
i
<
=
m
,
d
p
[
n
]
[
m
]
a n s=\sum d p[n][i], 0<=i<=m, d p[n][m]
ans=∑dp[n][i],0<=i<=m,dp[n][m]
状态转移方程同第三种情况。
其实允许空盒就是可以不用把 m 个盒子全部用完,那么就直接在上一种情况的基础上枚举实际用到的盒子的个数,将答案累加起来就可以了。
球不同 盒不同 无空箱
a
n
s
=
m
!
×
d
p
(
n
,
m
)
a n s=m ! \times d p(n, m)
ans=m!×dp(n,m)
较第三种情况就多了盒的有序性,dp(n,m)是相同的情况,m!是考虑顺序。
球不同 盒不同 允许空箱
a
n
s
=
m
n
a n s=m^{n}
ans=mn
每个球都有m种选择,所以就等于m^n。
球相同 盒相同 无空箱
d
p
[
n
]
[
m
]
=
d
p
[
n
−
m
]
[
m
]
(
n
>
=
m
)
d
p
[
n
]
[
m
]
=
0
(
n
<
m
)
\begin{array}{c} d p[n][m]=d p[n-m][m] \quad(n>=m) \\ d p[n][m]=0(n<m) \end{array}
dp[n][m]=dp[n−m][m](n>=m)dp[n][m]=0(n<m)
dp[n][m]表示已放进n个球 , 有m个盒子。
球相同 盒相同 允许空箱
d
p
[
n
]
[
m
]
=
d
p
[
n
]
[
m
−
1
]
+
d
p
[
n
−
m
]
[
m
]
(
n
>
=
m
)
d
p
[
n
]
[
m
]
=
d
p
[
n
]
[
m
−
1
]
(
n
<
m
)
边界:
d
p
[
k
]
[
1
]
=
1
\begin{array}{c} d p[n][m]=d p[n][m-1]+d p[n-m][m](n>=m) \\ d p[n][m]=d p[n][m-1](n<m) \\ \text { 边界: } d p[k][1]=1 \end{array}
dp[n][m]=dp[n][m−1]+dp[n−m][m](n>=m)dp[n][m]=dp[n][m−1](n<m) 边界: dp[k][1]=1
dp[n][m]表示已放进n个球 , 有m个盒子。
考虑小球比盒子多时,可以选择将盘子不放满或者放满分别对应 dp [ n ] [ m − 1 ] 和 d p [ n − m ] [ m ] .
但小球比盒子少时,已经不存在放满的情况了,直接dp[n][m-1]。
容斥原理
∣ A 1 ∪ A 2 ∪ ⋯ ∪ A m ∣ = ∑ 1 ≤ i ≤ m ∣ A i ∣ − ∑ 1 ≤ i < j ≤ m ∣ A i ∩ A j ∣ + ∑ 1 ≤ i < j < k ≤ m ∣ A i ∩ A j ∩ A k ∣ − ⋯ + ( − 1 ) m − 1 ∣ A 1 ∩ A 2 ∩ ⋯ ∩ A m ∣ \begin{array}{l} \left|A_{1} \cup A_{2} \cup \cdots \cup A_{m}\right|= \\ \sum_{1 \leq i \leq m}\left|A_{i}\right|-\sum_{1 \leq i<j \leq m}\left|A_{i} \cap A_{j}\right|+\sum_{1 \leq i<j<k \leq m}\left|A_{i} \cap A_{j} \cap A_{k}\right|-\cdots+(-1)^{m-1}\left|A_{1} \cap A_{2} \cap \cdots \cap A_{m}\right| \end{array} ∣A1∪A2∪⋯∪Am∣=∑1≤i≤m∣Ai∣−∑1≤i<j≤m∣Ai∩Aj∣+∑1≤i<j<k≤m∣Ai∩Aj∩Ak∣−⋯+(−1)m−1∣A1∩A2∩⋯∩Am∣
void dfs(int id,int ge,ll sum){
if(id>4) return;
dfs(id+1,ge,sum);
++ge; sum*=a[id];
dfs(id+1,ge,sum);
if(ge%2==0) ans-=n/sum;
else ans+=n/sum;
}
基础数论
逆元
(a + b) % p == ( a%p + b%p )%p
(a - b) % p == ( a%p - b%p )%p
(a * b) % p == ( a%p * b%p )%p
除法不满足
定义若
mod p
意义下 , 对于一个整数a
, 有a*x == 1 ( mod p )
, 那么这个整数x
即为a
的乘法逆元 , 同时a
也为x
的乘法逆元[充要条件] :
a
存在 模p 的乘法逆元的充要条件是gcd(a,p)==1
, 即a与p互质
应用 : 求取
(a/b)%p
等同于a*(b的逆元)%p
根据的第二条费马小定理 :
只要
b
不是p的倍数那么b*(b^p-2) == 1( mod p ) --> b%p * ( (b^p-2)%p ) % p == 1 % p所以我们只需要把
(b^p-2)%p
当做b的逆元来计算即可即
(a/b)%p
==( a%p* ( (b^(p-2) )%p) )%p
inline ll inv(ll tar){
tar=(tar%mod+mod)%mod;
return fpow(tar,mod-2);
}
inline ll inv(ll tar){
ll x,y;
tar=(tar%mod+mod)%mod;
ex_gcd(tar,mod,x,y);
x = (x%mod+mod)%mod;
return x;
}
则
(a/b)%p==( (a%p) * (x%p) )%p
费马小定理
假如
a
是一个整数 ,p
是一个质数
,那么1 , 如果a是p的倍数 , a^p == a( mod p )
2 , 如果a不是p的倍数 , a^(p-1) == 1 (mod p)
同余式 :
a==b ( mod n )
表示a和b对模n同余 , 集正整数a - b
能被n整除