清北学堂——1day
一.
数学基础知识:
1°:模运算:
a=k*b+r a mod b =r
(a±b) mod p=(a mod p+b mod p) mod p;
2°:最大公因数与最小公倍数:
存在g 使得g∣a,g∣b , g=gcd(a,b);
存在 l 使 a∣l , b∣l ,则l = lcm(a,b)
gcd(a,b) * lcm(a,b)=a*b
3°:辗转相除法:
gcd(a,b)=gcd(a,a-b)
gcd(a,b)=gcd(a,a%b)
gcd(a,0)=gcd(0,a)=a
4°:进制:
短除法
5°:高精度运算:
unsigned int 0~2^32-1
unsigned long long 0~2^64-1
高精度优化:压位:
引:k代表每个数组需要压几位
(1):输入输出:
1 int k=4; 2 int base=10000; 3 char s[3000]; 4 5 6 struct hpo{ 7 int n; 8 int z[256]; 9 hpo(){ 10 n=1; 11 memset(n,0,sizeof(z)); 12 } 13 void init() 14 { 15 scanf("%s",s+1); 16 int l=strlen(s+1); 17 reverse(s+1,s+1+l); 18 for(int i=1;i<=l;i+=k) 19 { 20 n++; 21 int bit=1; 22 for(int j=i;j<=i+k-1;j<=l;j++) 23 z[n]=z[n]+(s[j]-'0')*bit; 24 bit*=10; 25 } 26 27 } 28 void printf() 29 { 30 printf("%d",z[n]); 31 for(int i=n-1;i>=1;i--) 32 printf("%d"z[i]); 33 } 34 };
(2)高精度加法(压位):
1 hpo operator+(const hpo &a,const hpo &b) 2 { 3 hpo c; 4 c.n=max(a.n,b.n); 5 for(int i=1;i<=c.n;i++) 6 c.z[i]=a.z[i]+b.z[i]; 7 for(int i=1;i<=c.n;i++) 8 { 9 c.z[i+1]+=c.z[i]/base; 10 c.z[i]%=base; 11 } 12 if(c.z[c.n+1]!=0) c.n++; 13 return c; 14 }
(3)高精度乘法(压位):
hpo operator*(const hpo &a,const hpo &b) { hpo c; c.n=a.n+b.n; for(int i=1;i<=a.n;i++) for(int j=1;j<=b.n;j++) c.z[i+j-1]=a.z[i]*b.z[j]; for(int i=1;i<=c.n;i++) { c.z[i+1]=c.z[i]/base; c.z[i]%=base; } if(c.z[c.n]==0&&c.n!=1) c.n--; return c; }
6°:快速幂:
1 inline int fast_power(int a,int b,int c){ 2 int ans=1; 3 while(b){ 4 if(b&1) ans=1ll*a*ans%c; 5 a=1ll*a*a%c; 6 b/=2; 7 } 8 return ans%c; 9 }
二.
1°行列式:
行列式基础知识不再赘述
简要讲一下
行列式的消元方法
共计三种;
(1)基本消元
double z[110][110]; int n; double gauss() { double x=1; for (int a=1;a<=n;a++) { for (int b=a;b<=n;b++) if (fabs(z[b][a]) > 1e-8) { if (b==a) break; x=-x; for (int c=1;c<=n;c++) swap(z[b][c],z[a][c]); break; } if (fabs(z[a][a]) <= 1e-8) return 0.0; for (int b=a+1;b<=n;b++) { double k = z[b][a] / z[a][a]; for (int c=1;c<=n;c++) z[b][c] = z[b][c] - z[a][c] * k; } } for (int a=1;a<=n;a++) x=x*z[a][a]; return x; }
(2)主元消元:
1 double z[110][110]; 2 int n; 3 4 double gauss() 5 { 6 double x=1; 7 for (int a=1;a<=n;a++) 8 { 9 for (int b=a+1;b<=n;b++) 10 if (fabs(z[b][a]) > fabs(z[a][a])) 11 { 12 x=-x; 13 for (int c=1;c<=n;c++) 14 swap(z[b][c],z[a][c]); 15 } 16 if (fabs(z[a][a]) <= 1e-8) return 0.0; 17 for (int b=a+1;b<=n;b++) 18 { 19 double k = z[b][a] / z[a][a]; 20 for (int c=1;c<=n;c++) 21 z[b][c] = z[b][c] - z[a][c] * k; 22 } 23 } 24 for (int a=1;a<=n;a++) 25 x=x*z[a][a]; 26 return x; 27 }
(3)辗转相消:
1 int z[110][110],n; 2 void gauss() 3 { 4 int x=1; 5 for(int i=1;i<=n;i++) 6 { 7 for(int j=i+1;j<=n;j++) 8 { 9 10 while(z[b][a]!=0){ 11 int k=z[a][a]/z[b][a]; 12 for(int u=1;u<=n;u++) 13 z[a][u]=z[a][u]-z[b][u]*k; 14 for(int u=1;u<=n;u++) 15 swap(z[b][v],z[a][v]); 16 x=-x; 17 18 } 19 } 20 } 21 for (int a=1;a<=n;a++) 22 x=x*z[a][a]; 23 return x; 24 }
在下比较推荐第三种消元方法
当然我也只会第三种
相比较来说
这三种消元方法
时间复杂度都是O(n^3)
但相对来说辗转相消没有运行过程中的精度误差
2°:矩阵
矩阵基本知识不多说
矩阵乘法代码:
1 struct matrix{ 2 int n,m; 3 int z[256][256]; 4 matrix() 5 { 6 n=m=0; 7 memset(z,0,sizeof(z)); 8 } 9 }; 10 matrix operator(const matrix &a,const matrix &b) 11 { 12 matrix c; 13 c.n=a.n; 14 c.m=b.m; 15 for(int i=1;i<=c.n;i++) 16 for(int j=1;j<=c.m;j++) 17 for(int l=1;l<=a.m;l++) 18 c.z[i][j]=c.z[i][j]+a.z[i][k]*b.z[k][j]; 19 return c; 20 }
使用矩阵可以进一步的优化程序
例如;
斐波那契数列的优化
1 struct matrix 2 { 3 int n,m; 4 int z[233][233]; 5 matrix() 6 { 7 n=m=0; 8 memset(z,0,sizeof(z)); 9 } 10 }; 11 12 matrix operator*(const matrix &a,const matrix &b) 13 { 14 matrix c; 15 c.n = a.n; 16 c.m = b.m; 17 for (int i=1;i<=c.n;i++) 18 for (int j=1;j<=c.m;j++) 19 for (int k=1;k<=a.m;k++) 20 c.z[i][j] = c.z[i][j] + a.z[i][k] * b.z[k][j]; 21 return c; 22 } 23 24 25 matrix ksm(matrix x,int y) 26 { 27 if (y==0) 28 { 29 matrix z; 30 z.n=z.m=x.n; 31 for (int a=1;a<=z.n;a++) 32 z.z[a][a] = 1; 33 return z; 34 } 35 matrix z = ksm(x,y>>1); 36 z = z*z; 37 if (y%2==1) z=z*x; 38 return z; 39 } 40 41 int main() 42 { 43 m1 = [1,0]; 44 m2 = [[1,1],[1,0]]; 45 m1 * ksm(m2,n-1) = [fn,fn-1]; 46 }
先使用矩阵优化
简化成:[f(1) f(0)] * [{1 1} {1 1}]^n-1=[f(n) f(n-1)]
之后可以使用快速幂进一步优化
矩阵还可以用来优化dp
优化式一定长这样:
f[i][j]=∑(k)f[i-1][k]*M[k][j]
不过必须符合以下2个条件
2:由dp[i-1]->dp[i]
3:M[k][j]与i无关
-end-