清北学堂——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-

 

        

posted @ 2020-03-09 12:40  ·Iris  阅读(276)  评论(0编辑  收藏  举报