快速幂矩阵 难在构造
void mul(int c[], int a[], int b[][N])//a*b=c a是行向量 b是矩阵
{
int temp[N] = {0};//缓存矩阵 因为mul传入的c矩阵和a矩阵 可能是相同的 你不能一边读一边改
for (int i = 0; i < N; i ++ )
for (int j = 0; j < N; j ++ )
temp[i] = (temp[i] + (LL)a[j] * b[j][i]) % m;
memcpy(c, temp, sizeof temp);//只能用局部变量
}
void mul(int c[][N], int a[][N], int b[][N])//矩阵乘矩阵
{
int temp[N][N] = {0};//缓存矩阵 因为mul传入的c矩阵和a矩阵 可能是相同的 你不能一边读一边改
for (int i = 0; i < N; i ++ )//
for (int j = 0; j < N; j ++ )
for (int k = 0; k < N; k ++ )
temp[i][j] = (temp[i][j] + (LL)a[i][k] * b[k][j]) % m;
memcpy(c, temp, sizeof temp);
}
while (n)
{
if (n & 1) mul(f1, f1, a); // res = res * a 向量乘矩阵
mul(a, a, a); // a = a * a 矩阵*矩阵
n >>= 1;
}
求斐波那且的前n项和sn https://www.acwing.com/activity/content/problem/content/1756/
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int N = 3;
int n, m;
ll A[N][N] = // 上述矩阵 A
{
{2, 0, -1},
{1, 0, 0},
{0, 1, 0}
};
ll S[N] = {2, 1, 0}; // 上述矩阵 S(转置)
void multi(ll A[], ll B[][N]) // 计算方阵 B 乘向量 A,并将结果储存在 A 中
{
ll ans[N] = {0};
for (int i = 0; i < N; i ++ )
for (int j = 0; j < N; j ++ )
ans[i] += A[j] * B[i][j] % m;
for (int i = 0; i < N; i ++ )
A[i] = ans[i] % m;
}
void multi(ll A[][N], ll B[][N]) // 计算方阵 A * B,并将结果储存在 A 中
{
ll ans[N][N] = {0};
for (int i = 0; i < N; i ++ )
for (int j = 0; j < N; j ++ )
for (int k = 0; k < N; k ++ )
ans[i][j] += A[i][k] * B[k][j] % m;
for (int i = 0; i < N; i ++ )
for (int j = 0; j < N; j ++ )
A[i][j] = ans[i][j] % m;
}
int main()
{
scanf("%d%d", &n, &m);
n-=1; //注意这里也要少一项 因为我们去求的是 f1*a^(n-1)
while (n) // 矩阵快速幂
{
if (n & 1) multi(S, A);
multi(A, A);
n >>= 1;
}
printf("%lld", (S[2] % m + m) % m);
return 0;
}
佳佳的斐波那契https://www.acwing.com/activity/content/problem/content/1757/
求1f1+2f2+3f3+4f4....n*fn因为这里的数字不固定 所以换个方法
发现可以用pn-pn-1表示
这里需要 fn fn+1 sn pn+1
pn+1是发现满足某项和下一项相差一个固定矩阵时候可用
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 4;
int n, m;
void mul(int c[][N], int a[][N], int b[][N]) // c = a * b
{
static int t[N][N];
memset(t, 0, sizeof t);
for (int i = 0; i < N; i ++ )
for (int j = 0; j < N; j ++ )
for (int k = 0; k < N; k ++ )
t[i][j] = (t[i][j] + (LL)a[i][k] * b[k][j]) % m;
memcpy(c, t, sizeof t);
}
int main()
{
cin >> n >> m;
// {fn, fn+1, sn, pn}
// pn = n * sn - tn
int f1[N][N] = {1, 1, 1, 0};
int a[N][N] = {
{0, 1, 0, 0},
{1, 1, 1, 0},
{0, 0, 1, 1},
{0, 0, 0, 1},
};
int k = n - 1;
// 快速幂
while (k)
{
if (k & 1) mul(f1, f1, a); // f1 = f1 * a
mul(a, a, a); // a = a * a
k >>= 1;
}
cout << (((LL)n * f1[0][2] - f1[0][3]) % m + m) % m << endl;
return 0;
}