有 志 者 事 竟 成,破 釜 沉 舟,百 二 秦 关 终 属 楚;
苦 心 人 天 不 负,卧 薪 尝 胆,三 千 越 甲 可 吞 吴!
LDU暑假第一次学习记
今天学习了一波矩阵快速幂,受益良多!!!
矩阵快速幂的目的就斐波那契这个例子来说,是把一个递推式,换成可以类似于一个数一样,来进行快速幂运算。已达到在log(n)的复杂度内实现求第n项。
首先亮出我的矩阵快速幂模板
#define mat_mod 2009
struct Mat {
ll m[10][10];
};
Mat Mul(Mat A, Mat B, ll mat_size) {
Mat res;
memset(res.m, 0, sizeof(res.m));
for (int i = 0; i < mat_size; i++)for (int j = 0; j < mat_size; j++)for (int k = 0; k < mat_size; k++)
res.m[i][j] = (res.m[i][j] + (A.m[i][k] * B.m[k][j]) % mat_mod) % mat_mod;
return res;
}
Mat mat_qpow(Mat data, ll power, ll mat_size) {
Mat res;
memset(res.m, 0, sizeof(res.m));
for (int i = 0; i < mat_size; i++)res.m[i][i] = 1;
while (power) {
if (power & 1)res = Mul(res, data, mat_size);
data = Mul(data, data, mat_size), power >>= 1;
}
return res;
}
用法也很简单
int main()
{
//前提修改mod不可将mod传参,否则很慢
Mat temp;
memset(temp.m, 0, sizeof(temp.m));
temp = mat_qpow(temp, 2000, 10);
}
知道怎么用了之后,咱们就开始解决如何使用应用矩阵快速幂。
根据对应关系,得出一个矩阵。通过递归得到最后的ans
就拿Fibonacci数列的前n项和举例子吧。
首先咱们要有几个对应的关系式
Fn=Fn-1+Fn-2
Sn=Sn-1+Fn
然后咱们列出对应矩阵关系
( f n f n − 1 S n ) = ( _ _ _ _ _ _ _ _ _ ) × ( f n − 1 f n − 2 S n − 1 ) 通 过 求 解 得 出 矩 阵 为 ( 1 1 0 1 0 0 1 1 1 ) \begin{pmatrix} f_{n} \\ f_{n-1}\\S_{n} \end{pmatrix}=\begin{pmatrix} \_ & \_ &\_ \\ \_ & \_ &\_ \\\_ & \_ &\_ \end{pmatrix}\times \begin{pmatrix} f_{n-1} \\ f_{n-2} \\S_{n-1}\end{pmatrix} \\通过求解得出矩阵为\\\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix} ⎝⎛fnfn−1Sn⎠⎞=⎝⎛_________⎠⎞×⎝⎛fn−1fn−2Sn−1⎠⎞通过求解得出矩阵为⎝⎛111101001⎠⎞
这应该如何理解呢,其实就是对应的系数组成矩阵,因为fn=1×fn-1+1×fn-2。fn-1=1×fn-1。Sn=1×Sn-1+1×fn=1×Sn-1+1×fn-1+1×fn-2
然后通过递归化简得到了最终的结果。演示一下过程
( f n f n − 1 S n ) = ( 1 1 0 1 0 0 1 1 1 ) × ( f n − 1 f n − 2 S n − 1 ) = ( 1 1 0 1 0 0 1 1 1 ) × ( 1 1 0 1 0 0 1 1 1 ) × ( f n − 2 f n − 3 S n − 2 ) = ( 1 1 0 1 0 0 1 1 1 ) 2 × ( f n − 2 f n − 3 S n − 2 ) . . . . . = ( 1 1 0 1 0 0 1 1 1 ) n − 2 × ( f 2 f 1 S 2 ) \begin{pmatrix} f_{n} \\ f_{n-1}\\S_{n} \end{pmatrix}=\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}\times \begin{pmatrix} f_{n-1} \\ f_{n-2} \\S_{n-1}\end{pmatrix}=\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}\times\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}\times \begin{pmatrix} f_{n-2} \\ f_{n-3} \\S_{n-2}\end{pmatrix}=\\\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}^{2}\times \begin{pmatrix} f_{n-2} \\ f_{n-3} \\S_{n-2}\end{pmatrix}.....=\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}^{n-2}\times \begin{pmatrix} f_{2} \\ f_{1} \\S_{2}\end{pmatrix} ⎝⎛fnfn−1Sn⎠⎞=⎝⎛111101001⎠⎞×⎝⎛fn−1fn−2Sn−1⎠⎞=⎝⎛111101001⎠⎞×⎝⎛111101001⎠⎞×⎝⎛fn−2fn−3Sn−2⎠⎞=⎝⎛111101001⎠⎞2×⎝⎛fn−2fn−3Sn−2⎠⎞.....=⎝⎛111101001⎠⎞n−2×⎝⎛f2f1S2⎠⎞
从而得到
( f n + 1 f n S n + 1 ) = ( 1 1 0 1 0 0 1 1 1 ) n − 1 × ( f 2 f 1 S 2 ) \begin{pmatrix} f_{n+1} \\ f_{n}\\S_{n+1} \end{pmatrix}=\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}^{n-1}\times \begin{pmatrix} f_{2} \\ f_{1} \\S_{2}\end{pmatrix} ⎝⎛fn+1fnSn+1⎠⎞=⎝⎛111101001⎠⎞n−1×⎝⎛f2f1S2⎠⎞
结果一目了然,直接利用这个关系式得出对应的值。
题目描述
我们知道斐波那契数列, F0=0, F1=1, Fn=Fn−1+Fn−2,求Fn mod 10000 。
输入
多组数据,每组数据一行,一个整数 n。
输入以 -1 结束。
输出
对于每组数据,输出 Fn mod 10000。
Sample Input
0
9
999999999
1000000000
-1
Sample Output
0
34
626
6875
Hint
n ≤ 109
题目分析
矩阵快速幂的基本应用
这里的矩阵关系为 M a t = ( 1 1 1 0 ) Mat=\begin{pmatrix} 1& 1 \\ 1 & 0 \end{pmatrix} Mat=(1110)
( f n + 1 f n ) = M a t n − 1 × ( f 2 f 1 ) \begin{pmatrix} f_{n+1} \\ f_{n} \end{pmatrix}=Mat^{n-1} \times\begin{pmatrix} f_{2} \\ f_{1} \end{pmatrix} (fn+1fn)=Matn−1×(f2f1)
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#pragma warning(disable:4244)
#define PI 3.141592653589793
#pragma GCC optimize(2)
#define accelerate cin.tie(NULL);cout.tie(NULL);ios::sync_with_stdio(false);
#define EPS 1.0e-8
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll ll_inf = 9223372036854775807;
const int int_inf = 2147483647;
const short short_inf = 32767;
const char char_inf = 127;
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline ll read() {
ll c = getchar(), Nig = 1, x = 0;
while (!isdigit(c) && c != '-')c = getchar();
if (c == '-')Nig = -1, c = getchar();
while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
return Nig * x;
}
inline void out(ll a) {
if (a < 0)putchar('-'), a = -a;
if (a >= 10)out(a / 10);
putchar(a % 10 + '0');
}
ll phi(ll n)
{
ll ans = n, mark = n;
for (ll i = 2; i * i <= mark; i++)
if (n % i == 0) { ans = ans * (i - 1) / i; while (n % i == 0)n /= i; }
if (n > 1)ans = ans * (n - 1) / n; return ans;
}
ll qpow(ll x, ll n, ll mod) {
ll res = 1;
while (n > 0) {
if (n & 1)res = (res * x) % mod;
x = (x * x) % mod;
n >>= 1;
}
return res;
}
struct Mat {
ll m[10][10];
};
Mat Mat_mul(Mat x, Mat y, ll mat_size, ll mod) {
Mat temp;
memset(temp.m, 0, sizeof(temp));
for (int i = 0; i < mat_size; i++)for (int j = 0; j < mat_size; j++)for (int k = 0; k < mat_size; k++)
temp.m[i][j] = (temp.m[i][j] % mod + x.m[i][k] * y.m[k][j]) % mod;
return temp;
}
Mat Create_identity_matrix(ll mat_size) {
Mat temp;
memset(temp.m, 0, sizeof(temp.m));
for (int i = 0; i < mat_size; i++)temp.m[i][i] = 1;
return temp;
}
Mat mat_qpow(Mat* mat, ll power, ll mat_size, ll mod) {
Mat res = Create_identity_matrix(mat_size);
while (power) {
if (power & 1) res = Mat_mul(res, *mat, mat_size, mod);
*mat = Mat_mul(*mat, *mat, mat_size, mod), power >>= 1;
}
return res;
}
#define Floyd for(int k = 1; k <= n; k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
#define read read()
int main()
{
Mat temp;
while (1)
{
ll n = read;
if (n == -1)break;
if (!n) { puts("0"); continue; }
temp.m[0][0] = temp.m[0][1] = temp.m[1][0] = 1;
temp.m[1][1] = 0;
temp = mat_qpow(&temp, n - 1, 2, 10000);
out((temp.m[1][0] + temp.m[1][1]) % 10000);
puts("");
}
}
PS:
上述的代码的矩阵快速幂有些慢,原因在于传的参数过多,修改成开头放置的就可。思路没变,只需要修改模板就可以。
By-轮月