zoukankan      html  css  js  c++  java
  • 【学习笔记】矩阵快速幂

    算法介绍

    前置芝士:矩阵 矩阵乘法
    这两个芝士并不是很难
    重点可能在应用方面

    首先介绍我所理解的广义的矩阵乘法:现在我们手上有两个矩阵(A)(B),我们期望得到一个答案矩阵(Ans) 其中(Ans[i][j] = Ans[i][j] + (A[i][k] * B[i][k]) 其中 + * 代一种运算(如 min max 等等))
    都可以用矩阵快速幂把递推的时间从(O(n)减到O(logn))

    先放一下矩阵快速幂的代码吧 类比快速幂即可

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define MOD 1000000007
    using namespace std;
    
    ll m,k;
    
    inline ll read(){
    	ll f = 1,ans = 0;
    	char a = getchar();
    	while((a < '0' || a > '9') && a != '-') a = getchar();
    	if(a == '-') f = -1,a = getchar();
    	while(a <= '9' && a >= '0') ans = (ans << 3) + (ans << 1) + (a ^ 48),a = getchar();
    	return f * ans;
    } 
    
    struct map{
    	ll a[200][200];
    	map(){
    		memset(a,0,sizeof(a));
    	}
    	void in(){
    		for(ll i = 1;i <= m;i++)
    		for(ll j = 1;j <= m;j++)
    		a[i][j] = read();
    	}
    	void out(){
    		for(ll i = 1;i <= m;i++,puts(""))
    		for(ll j = 1;j <= m;j++)
    		cout<<a[i][j]<<" ";
    	}
    }ai,ans;
    
    map operator * (const map &a,const map &b){
    	map c;
    	for(ll k = 1;k <= m;k++)
    	for(ll i = 1;i <= m;i++)
    	for(ll j = 1;j <= m;j++)
    	c.a[i][j] = (c.a[i][j] + (a.a[i][k] * b.a[k][j]) % MOD)% MOD;
    	return c;
    }
    
    void quick(ll k){
    	while(k){
    		if(k & 1) ans = ans * ai;
    		ai = ai * ai;
    		k >>= 1;
    	}
    }
    int main(){
    	m = read();
    	k = read() - 1;
    	ai.in();
    	ans = ai;
    	quick(k);
    	ans.out();
    }
    

    例题

    前面说了 矩阵快速幂重点在于应用
    下面给出两种我最近见到的题

    构造矩阵

    P1939 【模板】矩阵加速(数列)
    根据题目,我们的目标矩阵是这样的

    [ egin{matrix} f[i] \ f[i - 1] \ f[i - 2] end{matrix} ]

    然后我们发现

    [ egin{matrix} f[i]=f[i−1]×1+f[i−2]×0+f[i−3]×1 \ f[i−1]=f[i−1]×1+f[i−2]×0+f[i−3]×0 \ f[i−2]=f[i−1]×0+f[i−2]×1+f[i−3]×00 end{matrix} ]

    观察系数 我们构造出这样一个递归矩阵

    [ egin{matrix} 1 & 0 & 1 \ 1 & 0 & 0 \ 0 & 1 & 0 end{matrix} ]

    接下来就是套路的快速幂了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define MOD 1000000007
    using namespace std;
    
    ll m = 3,k,T;
    
    inline ll read(){
    	ll f = 1,ans = 0;
    	char a = getchar();
    	while((a < '0' || a > '9') && a != '-') a = getchar();
    	if(a == '-') f = -1,a = getchar();
    	while(a <= '9' && a >= '0') ans = (ans << 3) + (ans << 1) + (a ^ 48),a = getchar();
    	return f * ans;
    } 
    
    struct map{
    	ll a[200][200];
    	map(){
    		memset(a,0,sizeof(a));
    	}
    	void aiin(){
    		memset(a,0,sizeof(a));		
    		a[1][1] = a[1][3] = a[2][1] = a[3][2] = 1;
    	}
    	void ansin(){
    		memset(a,0,sizeof(a));
    	    a[1][1] = a[2][2] = a[3][3] = 1; 
    	}
    }ai,ans;
    
    map operator * (const map &a,const map &b){
    	map c;
    	for(ll k = 1;k <= 3;k++)
    	for(ll i = 1;i <= 3;i++)
    	for(ll j = 1;j <= 3;j++)
    	c.a[i][j] = (c.a[i][j] + (a.a[i][k] * b.a[k][j]) % MOD)% MOD;
    	return c;
    }
    
    void quick(ll k){
    	ans.ansin();
    	ai.aiin();
    	while(k){
    		if(k & 1) ans = ans * ai;
    		ai = ai * ai;
    		k >>= 1;
    	}
    }
    int main(){
    	T = read();
    	while(T --){
    		k = read();
    		if(k <= 3)
    		{puts("1");continue;} 
    		else
    		quick(k),cout<<ans.a[2][1]<<endl;
    	} 
    }
    

    题目自带的矩阵

    P2886 [USACO07NOV]Cow Relays G
    题目大意算法就不再阐述 请看这里

  • 相关阅读:
    Silverlight如何logging?
    写一个Attribute用于标注类的核心函数, 方便阅读
    WPF : 如何使用DataTemplateSelector
    WPF : 性能调整
    组成UI的元素
    DemoFlowControl
    对象设计: 数据边界(Data Scope)
    sql for xml path用法
    行列转置快速实现
    js移除数组中德重复数据
  • 原文地址:https://www.cnblogs.com/dixiao/p/13842953.html
Copyright © 2011-2022 走看看