牛客14532 没有名字 (循环矩阵乘法+快速幂)
题目链接:https://ac.nowcoder.com/acm/problem/14532
不难看出题目是用矩阵乘法来加速的,但显然时间复杂度 \(O(n^{3}logm)\) 过高
构造出矩阵后,打印出来发现,该矩阵是一个循环矩阵
设 \(a,b\) 均为循环矩阵,则有以下性质:
- \(a + b\) 是循环矩阵
- \(a * b\) 是循环矩阵
于是我们只要知道最初循环矩阵第一行的最终形态,就可以知道整个矩阵最终形态是什么了
设最初的循环矩阵为 \(S\), \(T\) 为 \(S\) 的转置矩阵,则
\(res[1][j] = \sum\limits_{k=1}^{n} S[1][k] * T[k][j]\)
时间复杂度降为 \(O(n^2logm)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 210;
const int M = 1000000007;
int T, n, m, k;
int c[maxn];
struct Mat{
int a[maxn][maxn];
Mat(){
for(int i = 0 ; i <= n ; ++i){
for(int j = 0 ; j <= n ; ++j){
a[i][j] = 0;
}
}
}
void build(){
for(int i = 1 ; i <= n ; ++i){
a[i][i] = 1;
}
}
Mat operator * (const Mat &B) const{
Mat res;
for(int j = 1 ; j <= n ; ++j){
for(int k = 1 ; k <= n ; ++k){
res.a[1][j] += 1ll * a[1][k] * B.a[j][k] % M;
res.a[1][j] %= M;
}
}
for(int i = 2 ; i <= n ; ++i){
res.a[i][1] = res.a[i - 1][n];
for(int j = 2 ; j <= n ; ++j){
res.a[i][j] = res.a[i - 1][j - 1];
}
}
return res;
}
};
Mat qsm(Mat i, int p){
Mat res;
res.build();
while(p){
if(p & 1) res = res * i;
p >>= 1;
i = i * i;
}
return res;
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
T = read();
while(T--){
n = read(), m = read(), k = read();
for(int i = 1 ; i <= n ; ++i) c[i] = read();
Mat ans, base;
for(int i = 1 ; i <= n ; ++i) ans.a[1][i] = c[i];
for(int i = 1 ; i <= n ; ++i){
for(int j = 1 ; j <= n ; ++j){
if((i != j) && (min(abs(j - i), n - abs(j - i)) < k)){
base.a[j][i] = k - min(abs(j - i), n - abs(j - i));
}
}
}
base = qsm(base, m);
ans = ans * base;
for(int i = 1 ; i <= n ; ++i) printf("%d ", ans.a[1][i]); printf("\n");
}
return 0;
}