牛客14532 没有名字 (循环矩阵乘法+快速幂)

题目链接:https://ac.nowcoder.com/acm/problem/14532

不难看出题目是用矩阵乘法来加速的,但显然时间复杂度 (O(n^{3}logm)) 过高

构造出矩阵后,打印出来发现,该矩阵是一个循环矩阵

(a,b) 均为循环矩阵,则有以下性质:

  1. (a + b) 是循环矩阵
  2. (a * b) 是循环矩阵

于是我们只要知道最初循环矩阵第一行的最终形态,就可以知道整个矩阵最终形态是什么了

设最初的循环矩阵为 (S), (T)(S) 的转置矩阵,则
(res[1][j] = sumlimits_{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("
");
	}
	
	return 0;
}
原文地址:https://www.cnblogs.com/tuchen/p/14379829.html