组合数
都是一些定义吧。。。
性质1. 1. 1 . ,从n n n 个东西中选k k k 个选和选n − k n-k n − k 个不选是一样的。
性质2. 2. 2 . ,从n + 1 n+1 n + 1 个东西中选k k k 个,可以在其中n n n 个东西中选k k k 个,剩下一个不选,也可以在其中n n n 个东西中选k − 1 k-1 k − 1 个,剩下一个选。
性质2. 2. 2 . 在预处理组合数时经常用到,如:
for (register int i=0;i<MAXN;++i){
C[i][0]=1,C[i][i]=1;
for (register int j=1;j<i;++j){
C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
}
}
还有一个神奇的性质,我们把( x + a ) n (x+a)^n ( x + a ) n 拆开,变成( x + a ) ( x + a ) . . . . (x+a)(x+a).... ( x + a ) ( x + a ) . . . . 发现x x x 的系数为k k k 时,相当于在n n n 个x x x 中选k k k 个,剩下n − k n-k n − k 个选a a a 所以系数为C n k C_n^k C n k ,所以,( x + a ) n = ∑ k = 0 n C n k x k a n − k (x+a)^n=\sum^n_{k=0}C^k_nx^ka^{n-k} ( x + a ) n = ∑ k = 0 n C n k x k a n − k
根据这个性质,我们把x = 1 x=1 x = 1 ,a = 1 a=1 a = 1 代入,发现∑ i = 0 n C n i = ( 1 + 1 ) n = 2 n \sum^n_{i=0}C^i_n=(1+1)^n=2^n ∑ i = 0 n C n i = ( 1 + 1 ) n = 2 n 。
把x = 1 x=1 x = 1 ,a = − 1 a=-1 a = − 1 代入,发现∑ i = 0 n ( − 1 ) i C n i = ( 1 + ( − 1 ) ) n = 0 \sum^n_{i=0}(-1)^iC^i_n=(1+(-1))^n=0 ∑ i = 0 n ( − 1 ) i C n i = ( 1 + ( − 1 ) ) n = 0
剩下的性质,自己脑补一些场景,也可以证明出来。
卡特兰数
所有奇卡特兰数,下标都满足n = 2 k − 1 n=2^k-1 n = 2 k − 1 (不知道有啥用,手动狗头)
前6 6 6 点基本上都是老生常谈了,长方形填充还是挺巧妙的。
考虑一个可行的方案,必有如图的一个长方形,它的一个顶点在阶梯上,另一个在阶梯的最下面的角上(标成红色),要不然整个长方形不可能填充完。
发现它上方和右方的小阶梯可以构成子状态,y y yy y y 一下,发现F ( n ) = ∑ i = 0 n − 1 ( F ( i ) + F ( n − i − 1 ) ) F(n)=\sum^{n-1}_{i=0}{(F(i)+F(n-i-1))} F ( n ) = ∑ i = 0 n − 1 ( F ( i ) + F ( n − i − 1 ) )
这不就是卡特兰数吗?
GCD&LCM
大家都知道g c d ( x , y ) gcd(x,y) g c d ( x , y ) =g c d ( y , x m o d y ) gcd(y,x\mod y) g c d ( y , x m o d y ) ,我们可以用如下的算法求g c d gcd g c d 。
int gcd(int x,int y){return x%y==0?y:gcd(y,x%y);}
我们发现一个数对一个小于它的数取模后至少缩小一半,所以算法复杂度为l o g ( n ) log(n) l o g ( n ) ,实际可能还更小。
拓展欧几里得算法
求a x + b y = c ax+by=c a x + b y = c 的正整数解。
首先根据裴蜀定理,我们知道:g c d ( a , b ) ∣ c gcd(a,b)|c g c d ( a , b ) ∣ c ,否则方程无解。
设d = c g c d ( a , b ) d=\frac{c}{gcd(a,b)} d = g c d ( a , b ) c ,则知道a x + b y = g c d ( a , b ) ax+by=gcd(a,b) a x + b y = g c d ( a , b ) 的解,我们把解出的x , y x,y x , y 都乘个d d d 就能得出原方程的解x ′ , y ′ x',y' x ′ , y ′ 。
考虑把问题简单化,只求a x + b y = g c d ( a , b ) ax+by=gcd(a,b) a x + b y = g c d ( a , b ) 的正整数解。
考虑如下的方程:
a x 1 + b y 1 = g c d ( a , b ) ax_1+by_1=gcd(a,b) a x 1 + b y 1 = g c d ( a , b )
b x 2 + ( a m o d b ) y 2 = g c d ( b , a m o d b ) bx_2+(a\mod b)y_2=gcd(b,a\mod b) b x 2 + ( a m o d b ) y 2 = g c d ( b , a m o d b )
我们知道g c d ( a , b ) = g c d ( b , a m o d b ) gcd(a,b)=gcd(b,a\mod b) g c d ( a , b ) = g c d ( b , a m o d b )
所以a x 1 + b y 1 = b x 2 + ( a m o d b ) y 2 ax_1+by_1=bx_2+(a\mod b)y_2 a x 1 + b y 1 = b x 2 + ( a m o d b ) y 2
又知道a m o d b = a − ⌊ a / b ⌋ × b a\mod b=a-\lfloor a/b \rfloor \times b a m o d b = a − ⌊ a / b ⌋ × b
我们把上面的柿子代入:
发现a x 1 + b y 1 = b x 2 + ( a − ⌊ a / b ⌋ × b ) y 2 ax_1+by_1=bx_2+(a-\lfloor a/b \rfloor \times b)y_2 a x 1 + b y 1 = b x 2 + ( a − ⌊ a / b ⌋ × b ) y 2
化一下:a x 1 + b y 1 = a y 2 + b ( x 2 − ⌊ a / b ⌋ × y 2 ) ax_1+by_1=ay_2+b(x_2-\lfloor a/b \rfloor \times y_2) a x 1 + b y 1 = a y 2 + b ( x 2 − ⌊ a / b ⌋ × y 2 )
对比两边系数,我们开心地发现x 1 = y 2 x_1=y_2 x 1 = y 2 ,y 1 = x 2 − ⌊ a / b ⌋ × y 2 y_1=x_2-\lfloor a/b \rfloor \times y_2 y 1 = x 2 − ⌊ a / b ⌋ × y 2 ,于是我们可以根据x 2 , y 2 x_2,y_2 x 2 , y 2 算出x 1 , y 1 x_1,y_1 x 1 , y 1
具体实现的时候,递归求解即可。
模板:
int gcd(int a,int b,int &d,int &x,int&y){
if(!b){
d=a,x=1,y=0;
return x;
}
else{
gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
return x;
}
BSGS (北上广深算法)
已知a , b , p a,b,p a , b , p ,求a x = b ( m o d p ) a^x=b(\mod p) a x = b ( m o d p ) 的正整数解。
考虑折半法,我们设B = P B=\sqrt{P} B = P ,将x x x 化为B × i − j B \times i-j B × i − j 的形式,其中i < B , j < B i<B,j<B i < B , j < B
将x x x 代入原柿子,发现a x = a B × i − j = a B × i / a j a^x=a^{B \times i-j}=a^{B \times i} / a^j a x = a B × i − j = a B × i / a j
把那个a j a^j a j 搞到右边,发现a B × i = b × a j a^{B \times i}=b \times a^j a B × i = b × a j
其中,左右两边只有i , j i,j i , j 两个变量,取值只有B B B 种可能。
考虑把b × a j b \times a^j b × a j 预处理出来,丢进一个m a p map m a p 或哈希表里面。
后面一个一个枚举a B × i a^{B \times i} a B × i ,查询m a p map m a p 或哈希表里面有没有。
思维比较简单,但是代码比较长。
时间复杂度O ( n ) O(\sqrt {n}) O ( n )
模板题:P2485 [SDOI2011]计算器
题解:
对于询问1. 1. 1 . ,快速幂即可。
对于询问2. 2. 2 . ,逆元即可,注意判断不存在的情况。(当然e x t g c d extgcd e x t g c d 也是可做的)
对于询问3. 3. 3 . ,需要运用B S G S BSGS B S G S 算法,具体实现时需要注意B × i − j B \times i-j B × i − j 可能为负,需要+ p +p + p 再取模,并且j = 0 j=0 j = 0 ,b × a j = b b \times a^j=b b × a j = b 也是合法的。
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+(ch^'0');
ch=getchar();
}
return x*f;
}
int p;
inline int ksm(int b,int k){
int ans=1;
while (k){
if (k&1) ans=(ans*b)%p;
b=(b*b)%p;
k>>=1;
}
return ans;
}
inline void Solve1(int T){//快速幂
while (T--){
int y=read(),z=read();p=read();
y%=p;
printf("%lld\n",ksm(y,z));
}
}
inline void Solve2(int T){//逆元
while (T--){
int y=read(),z=read();p=read();
y%=p,z%=p;
if (y==0&&z!=0){
printf("Orz, I cannot find x!\n");
continue;
}
printf("%lld\n",ksm(y,p-2)*z%p);
}
}
map<int,int>M;
inline void BSGS(int a,int b){
if (a==0&&b!=0){
printf("Orz, I cannot find x!\n");
return ;
}
int B=(int)sqrt(p);
M.clear();
int now=b%p;
M[now]=0;
for (register int i=1;i<=B;++i){
now=(now*a)%p;
M[now]=i;
}
now=1;
int S=ksm(a,B);
for (register int j=1;j<=B;++j){
//判断a^{B \times i}是否在表中
now=(now*S)%p;
if (M.count(now)){
int ans=j*B-M[now];//M[now]=i
printf("%lld\n",(ans%p+p)%p);
return ;
}
}
printf("Orz, I cannot find x!\n");
}
inline void Solve3(int T){//BSGS
while (T--){
int y=read(),z=read();p=read();
BSGS(y%p,z);
}
}
#undef int
int main(){
#define int long long
int T=read(),K=read();
if (K==1) Solve1(T);
else if (K==2) Solve2(T);
else Solve3(T);
}
EXCRT 扩展中国剩余定理
在中国剩余定理的基础上,膜数p 1 , p 2 , p 3 . . . , p n p_1,p_2,p_3...,p_n p 1 , p 2 , p 3 . . . , p n 可能不是质数:
假设现在我们已经求出前k − 1 k-1 k − 1 个方程的解了,设为是x x x :
设M = l c m ( p 1 , p 2 , . . . . p k − 1 ) M=lcm(p_{1},p_{2},....p_{k-1}) M = l c m ( p 1 , p 2 , . . . . p k − 1 ) ,那么我们发现前k − 1 k-1 k − 1 个方程的通解可以表示成x + M × a l b x+M \times alb x + M × a l b (这些解都可以成立),其中a l b alb a l b 是整数。
我们要求t t t ,使得x + M × t = a k ( m o d p k ) x+M \times t=a_k (\mod p_k) x + M × t = a k ( m o d p k ) ,也就是M × t = a k − x ( m o d p k ) M \times t =a_k-x(\mod p_k) M × t = a k − x ( m o d p k )
可以用e x t g c d extgcd e x t g c d 求解t t t ,解完t t t 后,就发现前k k k 个式子的一个解为x + t × M x+t \times M x + t × M
整体思路也就是把式子合并合并再合并。
话说这个东西和C R T CRT C R T 关系好像不是很大。
高斯消元
可以求解类似于
a 11 × x + a 12 × y + a 13 × z . . . . . . . = b 1 a_{11} \times x + a_{12} \times y + a_{13} \times z ....... = b_1
a 1 1 × x + a 1 2 × y + a 1 3 × z . . . . . . . = b 1
a 21 × x + a 22 × y + a 23 × z . . . . . . . = b 2 a_{21} \times x + a_{22} \times y + a_{23} \times z ....... = b_2
a 2 1 × x + a 2 2 × y + a 2 3 × z . . . . . . . = b 2
a 31 × x + a 32 × y + a 33 × z . . . . . . . = b 3 a_{31} \times x + a_{32} \times y + a_{33} \times z ....... = b_3
a 3 1 × x + a 3 2 × y + a 3 3 × z . . . . . . . = b 3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ........................................
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ........................................
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
的方程。
假设我们有三个式子,假设a l b alb a l b 为现在未知数个数,现在a l b alb a l b 为3 3 3 :
1 × x + 2 × y + 3 × z = 4... ( 1 ) 1 \times x + 2 \times y + 3 \times z = 4 ... (1)
1 × x + 2 × y + 3 × z = 4 . . . ( 1 )
2 × x + 3 × y + 4 × z = 5... ( 2 ) 2 \times x + 3 \times y + 4 \times z = 5 ... (2)
2 × x + 3 × y + 4 × z = 5 . . . ( 2 )
3 × x + 4 × y + 7 × z = 6... ( 3 ) 3 \times x + 4 \times y + 7 \times z = 6 ... (3)
3 × x + 4 × y + 7 × z = 6 . . . ( 3 )
我们把( 1 ) (1) ( 1 ) 中的x x x 设为主元,和( 2 ) ( 3 ) (2)(3) ( 2 ) ( 3 ) 式相减。
( 2 ) − ( 1 ) × 2 : − 1 × y + − 2 × z = − 3... ( 4 ) (2)-(1) \times 2 : -1 \times y + -2 \times z = -3 ... (4)
( 2 ) − ( 1 ) × 2 : − 1 × y + − 2 × z = − 3 . . . ( 4 )
( 3 ) − ( 1 ) × 3 : − 2 × y + − 2 × z = − 6... ( 5 ) (3)-(1) \times 3 : -2 \times y + -2 \times z = -6 ... (5)
( 3 ) − ( 1 ) × 3 : − 2 × y + − 2 × z = − 6 . . . ( 5 )
发现a l b = 2 alb=2 a l b = 2 ,继续执行一遍类似的操作,把( 4 ) (4) ( 4 ) 中的y y y 设为主元,和( 5 ) (5) ( 5 ) 式相减。
( 5 ) − ( 4 ) × 2 : 2 × z = 0 (5)-(4) \times 2 : 2 \times z = 0
( 5 ) − ( 4 ) × 2 : 2 × z = 0
我们就成功地解出了z z z ,把z z z 往上带,可以求出x x x ,y y y ,就可以解出方程。
不仅对于a l b = 3 alb=3 a l b = 3 的情况,a l b alb a l b 更大,也可以用类似的方法求出未知数。
时间复杂度O ( a l b 2 ) O(alb^2) O ( a l b 2 )
高斯消元的操作可以转换为矩阵操作,其实就是把一个普通矩阵转换为单位矩阵。
逆矩阵
单位矩阵e e e :只有主对角线为1 1 1 的矩阵
容易发现单位矩阵乘任意矩阵,任意矩阵乘单位矩阵都为其本身
于是定义一个n × n n\times n n × n 的矩阵A A A 的逆矩阵为A − 1 A^{-1} A − 1 满足A × A − 1 = e A \times A^{-1}=e A × A − 1 = e ;若B × A = C B \times A=C B × A = C ,则B = C ∗ A − 1 B=C*A^{-1} B = C ∗ A − 1
矩阵初等变换:交换两行/列,将一行/列的若干倍加到另一行/列上去(这些操作都可以通过左乘初等变换矩阵实现)
那么可以把A A A 搞成e e e 的变换矩阵就是A − 1 A^{-1} A − 1 了
过程就是高斯消元,开始在原矩阵的旁边维护一个e e e
对原矩阵的操作,都对这个矩阵也做一次
这样当A A A 变成e e e 了,原来的这个e e e 就变成A − 1 A^{-1} A − 1 了
我们可以把操作矩阵定义为C 1 , C 2 , . . . C k C_1,C_2,...C_k C 1 , C 2 , . . . C k ,发现A × C 1 × C 2 × C 3 . . . × C k = e A \times C_1 \times C_2 \times C_3 ... \times C_k=e A × C 1 × C 2 × C 3 . . . × C k = e ,
由于矩阵支持结合律,我们可以在这个式子两边同时乘以A − 1 A^{-1} A − 1 ,发现A × A − 1 × C 1 × C 2 × C 3 . . . × C k = e × A − 1 A \times A^{-1} \times C_1 \times C_2 \times C_3 ... \times C_k=e \times A^{-1} A × A − 1 × C 1 × C 2 × C 3 . . . × C k = e × A − 1
由于上面的两条性质A × A − 1 = e A \times A^{-1}=e A × A − 1 = e 和A × e = A A \times e = A A × e = A ,我们可以将式子化为e × C 1 × C 2 × C 3 . . . × C k = A − 1 e \times C_1 \times C_2 \times C_3 ... \times C_k = A^{-1} e × C 1 × C 2 × C 3 . . . × C k = A − 1
所以原来的e e e 就变为A − 1 A^{-1} A − 1 了,是不是很巧妙?
拉格朗日插值法
全然わからない!,似乎是一个构造函数的神奇方法,留个坑待填。
一道小水题 P4986