清明 DAY 1

数学基础
 
Part 1.  高精度计算
 

 
Part 2.  模意义下的运算
           
        mod 
对一个数取模,其实就是取余数
 
注意:
•   无除法运算
•   满足基本的交换律、分配率、结合律
•   对中间结果取模不影响最终答案
 

 
Part 3.  快速幂
 

 
Part 4.  费马小定理与GCD&LCM
 

 
Part 5.  素数与筛法
 

 
Part 6.  欧拉函数
 

 
矩阵
 

 

 

 

 

 

矩阵乘法

一个m×n的矩阵就是m×n个数排成m行n列的一个数阵
 
一个m×p的矩阵A    乘   一个p×n的矩阵B    得到一个矩阵   一个m×n的矩阵AB
 
其中

 

 

 

 应用:斐波那契数列

          •  求斐波那契数列第k项的值
 
解析:
  f(i)表示斐波那契数列第 i 项
举个例子:
f1=1       { 0  1          *         { f1            =        { f2
f2=1         1  1 }                     f2 }                      f3 }

                 2*2                      1*1                      1*1

 所以可以推出:

 

 那么问题来了:

 

最后用所求快速幂 * f1  f2 构成的(2*1)矩阵就得到结果

实际上只需要 a[0][0]*f1+a[0][1]*f2  , 因为我们最后只需要 f[k]

 

代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-1);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
ld eps=1e-9;
ll pp=1000000007;
ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
ll read(){
    ll ans=0;
    char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}
//head  
struct matrix{
    int a[2][2];
};
matrix operator *(matrix a, matrix b){
    matrix c;
    rep(i,0,1)
        rep(j,0,1){
            c.a[i][j]=0;
            rep(k,0,1)
                c.a[i][j] = (c.a[i][j]+a.a[i][k]*b.a[k][j])%pp;
        }
    return c;
}
int k;
int main(){
    cin>>k;
    matrix a;    //要乘的矩阵 
    a.a[0][0]=0;a.a[0][1]=1;
    a.a[1][0]=1;a.a[1][1]=1;
    
    matrix ans;   //答案矩阵,初始定义为 1(快速幂当中存答案的ans初始值就是1)
,此处处理为单位矩阵
ans.a[0][0]=1;ans.a[0][1]=0; ans.a[1][0]=0;ans.a[1][1]=1; int b=k-1; //就是矩阵要乘多少次(实际就是k-1次) while(b){ if(b%2==1)ans=ans*a; a=a*a; b/=2; } int fk = (ans.a[0][0]+ ans.a[0][1])%pp; //矩阵快速幂求完了,
最后要的答案运用矩阵乘法得到fk
cout<<fk<<endl; //O(log B *2^3) }

 

 

 拓展:

1.计算 f(n) = 4f(n-1) – 3f(n-2) + 2f(n-4) +bb 的第k项

【输入格式】

  第一行:四个数,分别为这个数列的第1,2,3,4项;

 第二行:一个数k表示要求的是这个数列的第几项,一个数bb。

【输出格式】

一个数,为这个数列的第k项

【输入样例】       【输出样例】

  1 2 3 4                     16(不对请指正)

  5 7

 

  解析:

 代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
typedef long long ll;#define rep(i,a,n) for(int i=a;i<=n;i++)
ll pp=1000000007;//head

struct xinde{
    int a[5][5];
};

xinde operator*(xinde a,xinde b){
    xinde c;
    rep(i,0,4)
      rep(j,0,4)
      {
          c.a[i][j]=0;
          rep(k,0,4)
          c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%pp;
      }
      return c;
}
int main()
{
    int bb,k,f1,f2,f3,f4;
    cin>>f1>>f2>>f3>>f4;
    cin>>k>>bb;
    
    xinde a;
    a.a[0][0]=0;a.a[0][1]=1;a.a[0][2]=0;a.a[0][3]=0;a.a[0][4]=0;
    a.a[1][0]=0;a.a[1][1]=0;a.a[1][2]=1;a.a[1][3]=0;a.a[1][4]=0;
    a.a[2][0]=0;a.a[2][1]=0;a.a[2][2]=0;a.a[2][3]=1;a.a[2][4]=0;
    a.a[3][0]=2;a.a[3][1]=0;a.a[3][2]=-3;a.a[3][3]=4;a.a[3][4]=1;
    a.a[4][0]=0;a.a[4][1]=0;a.a[4][2]=0;a.a[4][3]=0;a.a[4][4]=1;
    
    xinde ans;
    ans.a[0][0]=1;ans.a[0][1]=0;ans.a[0][2]=0;ans.a[0][3]=0;ans.a[0][4]=0;
    ans.a[1][0]=0;ans.a[1][1]=1;ans.a[1][2]=0;ans.a[1][3]=0;ans.a[1][4]=0;
    ans.a[2][0]=0;ans.a[2][1]=0;ans.a[2][2]=1;ans.a[2][3]=0;ans.a[2][4]=0;
    ans.a[3][0]=0;ans.a[3][1]=0;ans.a[3][2]=0;ans.a[3][3]=1;ans.a[3][4]=0;
    ans.a[4][0]=0;ans.a[4][1]=0;ans.a[4][2]=0;ans.a[4][3]=0;ans.a[4][4]=1;
    
    int b=k-1;
    while(b)
    {
        if(b%2==1)
        ans=ans*a;
        a=a*a;
        b/=2;
    }
    
    
    int fk=(ans.a[0][0]*f1+ans.a[0][1]*f2+ans.a[0][2]*f3+ans.a[0][3]*f4+ans.a[0][4]*bb)%pp;
    
    cout<<fk<<endl;
    
    return 0;
}

 

2.计算C(n,m)%p

   n<=10^18, m<=50
 
 解析:
  C(m , n+1)=C(m , n)+C(m-1 , n)
 

同样的道理

 
 
 
特殊矩阵:

1.邻接矩阵
   邻接矩阵(Adjacency Matrix)是表示顶点之间相邻关系的矩阵。

解释一下:

邻接矩阵中

A1[m][n] 表示从 Vm 到 Vn 有 A1[m][n] 条路(具体多少条路径还是要看图)

 性质:

      对无向图而言,邻接矩阵一定是对称的,而且主对角线一定为零,副对角线不一定为0,有向图则不一定如此。

 
 
 
2.三角矩阵
   三角矩阵是方形矩阵的一种,因其非零系数的排列呈三角形状而得名。
 
分类:
(1)上三角矩阵:一个矩阵如果对角线下方的元素全部为0,称为上三角矩阵
         性质:
        1)上三角矩阵的行列式为对角线元素相乘;
        2)上三角矩阵乘以系数后也是上三角矩阵;
        3)上三角矩阵间的加减法和乘法运算的结果仍是上三角矩阵;
        4)上三角矩阵的逆矩阵也仍然是上三角矩阵。
 
 (2)下三角矩阵:一个矩阵如果对角线上方的元素全部为0,称为下三角矩阵
 
 
 
3.分块矩阵
    分块矩阵是一个矩阵, 它是把矩阵分别按照横竖分割成一些小的子矩阵 。 然后把每个小矩阵看成一个元素。

分块矩阵*分块矩阵=分块矩阵

 

 

4.对角矩阵

       对角矩阵(diagonal matrix)是一个主对角线之外的元素皆为0的矩阵。

       对角线上的元素可以为0或其他值。

       对角线上元素相等的对角矩阵称为数量矩阵;

       对角线上元素全为1的对角矩阵称为单位矩阵。

             

 

5.单位矩阵

              

 

 6.对称矩阵
    对称矩阵(Symmetric Matrices)是指元素以主对角线为对称轴对应相等的矩阵。
 
 
 高斯消元
 
 
 行列式
 

行列式计算:

1.利用高斯消元将原矩阵变为对角矩阵
2.将对角线上的值连乘得到行列式

 

 
 
矩阵逆元
逆元的定义:
     若矩阵B*A=I 则称B为A的左逆元
     若矩阵A*B=I 则称B为A的左逆元
 
有逆元的前提:
     矩阵行列式不为0
 
 LH的矩阵求逆板子:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define N 405
using namespace std;
const int mod=1e9+7; template<class T>inline void rd(T &x){ x=0; short f=1; char c=getchar(); while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar(); while(c<='9' && c>='0') x=x*10+c-'0',c=getchar(); x*=f; } int n,m; int f[N][N<<1],r,ans; inline int qpow(int x,int k){ int ret=1; while(k){ if(k&1) ret=1LL*ret*x%mod; x=1LL*x*x%mod; k>>=1; } return ret; } inline void Gauss(){ for(int i=1;i<=n;i++){ for(int j=i;j<=n;j++) if(f[j][i]){ if(j!=i) for(int k=1;k<=m;k++) swap(f[i][k],f[j][k]); break; } if(!f[i][i]){puts("No Solution");exit(0);} r=qpow(f[i][i],mod-2); for(int j=i;j<=m;j++) f[i][j]=1LL*f[i][j]*r%mod; for(int j=1;j<=n;j++) if(j!=i){ r=f[j][i]; for(int k=i;k<=m;k++) f[j][k]=(f[j][k]-1LL*r*f[i][k]%mod+mod)%mod; } } for(int i=1;i<=n;i++){ for(int j=n+1;j<=m;j++) printf("%d ",f[i][j]); puts(""); } return; } int main(){ rd(n); m=n<<1; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++) rd(f[i][j]); f[i][n+i]=1; } Gauss(); return 0; }

 

 
 
扩充知识
然而后面这些知识点LH貌似没讲
矩阵树定理
 
一个图的邻接矩阵G:对于无向图的边(u,v),G[u][v]++,G[v][u]++
一个图的度数矩阵D:对于无向图的边(u,v),D[u][u]++,D[v][v]++
而通过这两个矩阵就可以构造出图G的基尔霍夫矩阵:C=D-G.
 
 Matrix Tree定理:
      将图G的基尔霍夫矩阵去掉第i行和第i列(i可以取任意值,可以证明所得到的结果相同),得到(n-1)*(n-1)的矩阵,对这个矩阵进行行列式的值求解,abs(det(A))即为图G的生成树个数。
 
 
 
 
有向图 - 矩阵树定理
 
树形图:以i点为根节点的树形图有(n-1)条边,从i节点出发可以到达其他所有(n-1)个节点.
 
定义: 有向图的邻接矩阵G:对于有向图的边(u,v),G[u][v]++.
            有向图的度数矩阵D:对于有向图的边(u,v),D[v][v]++.
 
尤其需要注意的是:有向图的度数矩阵指的是一个点的入度,而不是出度。
而有向图的基尔霍夫矩阵的构造方式是一模一样的:C=D-G.
 
有向图Matrix Tree定理:
        将有向图G的基尔霍夫矩阵去掉第i行和第i列,得到(n-1)*(n-1)的矩阵,对这个矩阵进行行列式的值求解,abs(det(A))就是以i为根的树形图的个数。
 
 
 
 
拓展:k^2logn求常系数线性递推方程
 
• f(n) = a0 + a1*f(n-1) + … + ak*f(n-k)
• 给出 f(1) ~ f(k), 求 f(n) % p
 
 

 

 
 
POJ 3735

 

 
 
 
 题解:

 

 

 
 
 
 
 
 
 
 
 

转载于:https://www.cnblogs.com/xiaoyezi-wink/p/10673517.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值