hdu1757 - A Simple Math Problem 矩阵快速幂
2015-04-26 12:02
375 查看
今天学矩阵突然开窍了
总结一下就是,矩阵乘法是没有实际意义的
(这里的意思是,在现实中找不到对应的东西,这是一个纯数学方法)
而且把原本普通算数可以做的事情转变成矩阵乘法是多此一举
比如说把点(x,y)左右平移10个单位,非常简单地可以想到变换后的坐标是(x+10,y)或者(x-10,y)。那为什么要用一个矩阵去表示这种变换呢?
因为矩阵乘法有结合律!
说点实际例子。
假设不使用矩阵乘法,那么平移之后,又想要进行旋转,颠倒等等一系列操作。 你可能说,接着算呗
那好,算完了 我给你第二个点,干刚才同样的事情 是不是又得从头到尾再算一遍?万一再给你一槽的点,是不是瞬间爆炸
那如果我们用矩阵乘法呢? 我们知道,平移可以用矩阵表示 实际上,旋转,缩放,翻转等,都可以用矩阵表示 具体怎么构造这些矩阵,问度娘。
那么假设原来的点坐标存放在矩阵x中(乘号右边一般都是列向量,乘号左边是则是行向量,这里假设变换矩阵都左乘)
那么乘以平移矩阵A,得到AX 乘以旋转矩阵B,得到BAX…… …… 处理到最后,假设结果变成FEDBCAX,别忘了我们是从右往左算的
但是他有结合律,这意味着我们可以改变计算顺序,先计算FEDBCA,再和X乘,得到的结果是相同的
以后要对另一个坐标做相同变换,我们只需要用计算好的FEDBCA再去左乘它就可。
假设我们要干同一件事情,但是没有很快的方法直接算到终点(比如说这题,一个数和前面的数有关系,还有斐波拉契等类似的数列),等下讲解。
上面是矩阵乘法的个人认识,
说回题目
面对这些数列题目,在学过矩阵快速幂之后都可以用矩阵快速幂来做了
这些题目的特点就是递推公式可以用变换矩阵表示出来。
表示成变换矩阵之后,递推n次其实就是左乘或者右乘 变换矩阵的n次幂
对于一个整形数,有如下快速幂黑科技,具体就不说了
快速幂的计算方法,是需要结合律的
矩阵乘法正好满足结合律
然后……就可以套上快速幂,变身矩阵快速幂
简直不要太神奇
再说回题目,题目的递推公式是
If x < 10 f(x) = x.
If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
那么我们做一个变换矩阵A,使得一个列向量
⎛⎝⎜⎜⎜⎜⎜⎜f(x−1)f(x−2)f(x−3)……f(x−10)⎞⎠⎟⎟⎟⎟⎟⎟
右乘他之后,得到结果为
⎛⎝⎜⎜⎜⎜⎜⎜f(x)f(x−1)f(x−2)……f(x−9)⎞⎠⎟⎟⎟⎟⎟⎟
然后求出矩阵A的k-9次幂,一乘,是不是结果就出来了?
构造出的矩阵A如下,具体构造方法,我目前只会凑233
⎛⎝⎜⎜⎜⎜⎜⎜⎜⎜a01a11a21a31…………a9⎞⎠⎟⎟⎟⎟⎟⎟⎟⎟
矩阵是瞎写的,不要在意,我很喜欢用const 233
总结一下就是,矩阵乘法是没有实际意义的
(这里的意思是,在现实中找不到对应的东西,这是一个纯数学方法)
而且把原本普通算数可以做的事情转变成矩阵乘法是多此一举
比如说把点(x,y)左右平移10个单位,非常简单地可以想到变换后的坐标是(x+10,y)或者(x-10,y)。那为什么要用一个矩阵去表示这种变换呢?
因为矩阵乘法有结合律!
说点实际例子。
假设不使用矩阵乘法,那么平移之后,又想要进行旋转,颠倒等等一系列操作。 你可能说,接着算呗
那好,算完了 我给你第二个点,干刚才同样的事情 是不是又得从头到尾再算一遍?万一再给你一槽的点,是不是瞬间爆炸
那如果我们用矩阵乘法呢? 我们知道,平移可以用矩阵表示 实际上,旋转,缩放,翻转等,都可以用矩阵表示 具体怎么构造这些矩阵,问度娘。
那么假设原来的点坐标存放在矩阵x中(乘号右边一般都是列向量,乘号左边是则是行向量,这里假设变换矩阵都左乘)
那么乘以平移矩阵A,得到AX 乘以旋转矩阵B,得到BAX…… …… 处理到最后,假设结果变成FEDBCAX,别忘了我们是从右往左算的
但是他有结合律,这意味着我们可以改变计算顺序,先计算FEDBCA,再和X乘,得到的结果是相同的
以后要对另一个坐标做相同变换,我们只需要用计算好的FEDBCA再去左乘它就可。
假设我们要干同一件事情,但是没有很快的方法直接算到终点(比如说这题,一个数和前面的数有关系,还有斐波拉契等类似的数列),等下讲解。
上面是矩阵乘法的个人认识,
说回题目
面对这些数列题目,在学过矩阵快速幂之后都可以用矩阵快速幂来做了
这些题目的特点就是递推公式可以用变换矩阵表示出来。
表示成变换矩阵之后,递推n次其实就是左乘或者右乘 变换矩阵的n次幂
对于一个整形数,有如下快速幂黑科技,具体就不说了
int QuickPow(int B ,int k) { int ans(1); while (k) { if (k&1) ans=ans*B%MOD; k>>=1; B = B*B %MOD ; } return ans; }
快速幂的计算方法,是需要结合律的
矩阵乘法正好满足结合律
然后……就可以套上快速幂,变身矩阵快速幂
简直不要太神奇
再说回题目,题目的递推公式是
If x < 10 f(x) = x.
If x >= 10 f(x) = a0 * f(x-1) + a1 * f(x-2) + a2 * f(x-3) + …… + a9 * f(x-10);
那么我们做一个变换矩阵A,使得一个列向量
⎛⎝⎜⎜⎜⎜⎜⎜f(x−1)f(x−2)f(x−3)……f(x−10)⎞⎠⎟⎟⎟⎟⎟⎟
右乘他之后,得到结果为
⎛⎝⎜⎜⎜⎜⎜⎜f(x)f(x−1)f(x−2)……f(x−9)⎞⎠⎟⎟⎟⎟⎟⎟
然后求出矩阵A的k-9次幂,一乘,是不是结果就出来了?
构造出的矩阵A如下,具体构造方法,我目前只会凑233
⎛⎝⎜⎜⎜⎜⎜⎜⎜⎜a01a11a21a31…………a9⎞⎠⎟⎟⎟⎟⎟⎟⎟⎟
矩阵是瞎写的,不要在意,我很喜欢用const 233
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<vector> #include<cmath> using namespace std; #define ll long long //Template mat //Interface here #define MULMOD //Use Matrix(int row,int cow) to define a new EMPTY matrix //Use Matrix(int n) to define a n*n identity matrix //Use define MULMOD and set MOD to ENABLE MOD #define MAXROWS 10 #define MAXCOLS 10 #ifdef MULMOD int MOD; #endif //Interface End struct Matrix { int Rows,Cols; ll data[MAXROWS][MAXCOLS]; void clear() { memset(data,0,sizeof(data)); } Matrix (int n,int m) :Rows(n),Cols(m) { clear(); } Matrix (int n) :Rows(n),Cols(n) { clear(); for (int i=0;i<n;i++) data[i][i]=1; } ll* operator[](const int n) { return data ; } Matrix operator* (const Matrix& ano) const { Matrix result(Rows,ano.Cols); for (int i=0;i<Rows;i++) for (int j=0;j<ano.Cols;j++) for (int k=0;k<Cols;k++) { #ifdef MULMOD result[i][j] += data[i][k] * ano.data[k][j] % MOD; result[i][j]%=MOD; #else result[i][j] += data[i][k] * ano.data[k][j]; #endif } return result; } }; Matrix QuickMatrixPow(Matrix to ,int k) { Matrix ans(to.Rows); for (int i=0;i<10;i++) ans[i][i]=1; while (k) { if (k&1) ans=ans*to; k>>=1; to = to*to; } return ans; } //Template mat end int main() { cin.sync_with_stdio(false); Matrix a(10,10); Matrix f0(10,1); int k,m; while (cin>>k>>m) { a.clear(); f0.clear(); MOD=m; for (int i=0;i<10;i++) //构造左乘矩阵 { cin>>a[0][i]; f0[i][0]=9-i; } for (int i=0;i<9;i++) a[i+1][i]=1; if (k<10) { cout<<f0[9-k][0]%m<<endl; continue; } //左乘一次得f(10) f(9) f(8) ……f(1)的矩阵 //两次 f(11) f(10) …… f(2) //所以要计算f(k),需要左乘 k-9次 //计算左乘的k-9个矩阵 cout <<( QuickMatrixPow(a,k-9) * f0)[0][0] %m <<endl; } }
相关文章推荐
- HDU1757-A Simple Math Problem(矩阵快速幂)
- hdu1757-- A Simple Math Problem(矩阵快速幂优化)
- hdu1757 A Simple Math Problem(矩阵快速幂)
- [HDU1757]A Simple Math Problem(矩阵快速幂)
- hdu1757 A Simple Math Problem(矩阵快速幂题解)
- HDU1757:A Simple Math Problem(矩阵快速幂)
- hdu1757 A Simple Math Problem (矩阵快速幂)
- HDU1757-A Simple Math Problem,矩阵快速幂,构造矩阵水过
- hdu1757 A Simple Math Problem(矩阵快速幂)
- hdu1757 - A Simple Math Problem 矩阵快速幂
- 【矩阵快速幂】 hdu1757 A Simple Math Problem
- Hdu1757 - A Simple Math Problem - 矩阵快速幂
- hdu1757 A Simple Math Problem【矩阵快速幂】
- hdu1757 A Simple Math Problem 矩阵快速幂 水题
- 2017 Wuhan University Programming Contest 现场赛 I. A simple math problem(矩阵快速幂)
- HDU 1757 A Simple Math Problem [矩阵快速幂]
- [HDU 1757] A Simple Math Problem (矩阵快速幂)
- HDU 1757 A Simple Math Problem 矩阵快速幂
- hdu 1757 A Simple Math Problem(矩阵快速幂)
- HDU 1757-A Simple Math Problem(矩阵快速幂)