• HDOJ5015 233 Matrix(矩阵乘法加速递推)


    原题链接:HDOJ5015

    题意简述:给定矩阵每个元素计算公式,求下标为(m,m)的元素的值。

    解题思路:刚开始想着递推求出整个矩阵,后来我哭了。m 可达1e9,要化简到 lg 级别才能不超时,这时我隐约想到用转移矩阵加快速幂做了,根据《算法竞赛进阶指南》P151页所述,如果一类问题具有如下特点:

    • 可以抽象出一个长度为n的一维向量,该向量在每个单位时间发生一次变化
    • 变化的形式是一个线性递推(只有若干“加法”或者“乘一个系数”的运算)
    • 该递推式在每个时间可能作用于不同的数据上,但本身保持不变
    • 向量变化时间(即递推的轮数)很长,但向量长度n不大。

    那么就可以考虑采用矩阵乘法进行优化。具体步骤就是构造出转移矩阵、状态矩阵,通过对转移矩阵的快速幂来加速递推。时间复杂度为(n^3 lgT),其中T为递推轮数。

    代码示例(如何构造转移矩阵于状态矩阵就不写了,手太冷了,而且我也讲不好):

    #include<cstdio>
    #include<cstring>
    const int maxn = 50;
    const int M = 10000007;
    struct Matrix{
    	int n;
    	int v[maxn][maxn];
    	Matrix(int n){
    		this->n = n;
    		memset(v,0,sizeof v);
    	}
    	Matrix operator *(const Matrix &b) const{
    		Matrix C(n);
    		for(int i = 0;i < n;i++)
    		for(int j = 0;j < n;j++)
    			for(int k = 0;k < n;k++)
    				C.v[i][j] = (C.v[i][j] + 1ll*v[i][k]*b.v[k][j]%M) % M;
    		return C;
    	}
    	Matrix operator +(const Matrix &b) const{
    		Matrix C(n);
    		for(int i = 0;i < n;i++)
    		for(int j = 0;j < n;j++)
    			C.v[i][j] = (v[i][j] + b.v[i][j])%M;
    		return C;
    	}
    	void qpow(int k){
    		Matrix E(n);
    		Matrix A = *this;
    		for(int i = 0;i < n;i++) E.v[i][i] = 1;
    		while(k){
    			if(k&1) E = E*A;
    			A = A*A;
    			k >>= 1;
    		}
    		*this = E;
    	}
    };
    int main(){
    	int n,m;
    	while(scanf("%d%d",&n,&m) != EOF){
    		Matrix tran(n+2);
    		for(int i = 0;i <= n;i++){
    			tran.v[i][0] = 10;
    			tran.v[i][n+1] = 1;
    		}
    		for(int i = 1;i <= n;i++)
    			for(int j = 1;j <= i;j++)
    				tran.v[i][j] = 1;
    		tran.v[n+1][n+1] = 1;
    		tran.qpow(m);
    		int t[n+2],ans[n+2];
    		memset(ans,0,sizeof ans);
    		t[0] = 23,t[n+1] = 3;
    		for(int i = 1;i <= n;i++)	scanf("%d",&t[i]);
    		for(int i = 0;i < n+2;i++)
    			for(int j = 0;j < n+2;j++)
    				ans[i] = (ans[i] + 1ll*tran.v[i][j]*t[j]%M)%M;
    		printf("%d
    ",ans[n]);
    	}
    	
    }
  • 相关阅读:
    数组名与指向数组的指针
    如何实现带可变长参数的函数
    assert()的使用
    参数入栈的顺序以及栈/堆的生长顺序
    指向函数的指针
    各变量入栈顺序
    数组与指针
    C中空指针、NULL与0
    C中为什么不能用==比较字符串?
    在命令行窗口中输入EOF
  • 原文地址:https://www.cnblogs.com/long98/p/10352151.html
Copyright © 2020-2023  润新知