浅谈循环矩阵的乘法和快速幂
前言
前置技能:矩阵乘法,矩阵快速幂
当然你不会的话也不会点进来(滑稽)
今天上午的
有一个长度为
n 的环,执行s 次操作,在一次操作中,对于每一个数,它变为它左边的数乘上
l 以及它本身以及它右边的数乘上r 的和。求最后每一个位置上的数是多少。(计算时左边和右边的数都是上一次的数)
最后结果模上
10^x ,l,r,x 都为给定的常数n\leq1000,s\leq2^{30}
很容易想到用矩阵快速幂来维护,假设我们现在有
但是这样子做是
这时我们发现,转移矩阵是一个循环矩阵。
循环矩阵是什么?
下面内容引自百度百科,侵删
在线性代数中,循环矩阵是一种特殊形式的
Toeplitz 矩阵,它的行向量的每个元素都是前一个行向量各元素依次右移一个位置得到的结果。
简单地说,就是以一行不断向前/后变换的形式出现。循环矩阵有一些性质
假设矩阵
a,b 都是循环矩阵,那么:
循环矩阵的乘法和矩阵快速幂
根据性质
假设
这里可以得出这个结果是根据了循环矩阵的定义。
那么其他的求法也是雷同的,比如
于是我们得出了这样的规律:
很显然,我们的初始矩阵
其中
那么之前所讲的例题再用矩阵快速幂就变成
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::min; using std::max;
using std::swap; using std::sort;
typedef long long ll;
template<typename T>
void read(T &x) {
int flag = 1; x = 0; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }
while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
}
const int N = 1e3 + 10;
int n, s, l, r, x, p = 1;
int S[N], T[N], tmp[N];
void mul(int S[], int T[]) {
memset(tmp, 0, sizeof tmp);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j)
(tmp[(i + j - 2) % n + 1] += 1ll * S[i] * T[j] % p) %= p;
memcpy(S, tmp, sizeof(tmp));
}//矩阵乘法
int main () {
read(n), read(s), read(l), read(r), read(x);
for(int i = 1; i <= x; ++i) p *= 10;
for(int i = 1; i <= n; ++i) read(S[i]);
T[1] = 1, T[2] = l, T[n] = r;
for(; s; s >>= 1, mul(T, T)) if(s & 1) mul(S, T);//快速幂
for(int i = 1; i <= n; ++i) printf("%d ", S[i]);
return 0;
}