FZU_1692
首先感觉输入数据里面的L和R应该反过来读取即先读入R再读入L,要不然样例算不出来,不知道是不是我理解错题意了。
矩阵不难构造,但这个题让进一步注意到了矩阵运算中的常熟优化:
①由于递推关系的矩阵各行是循环同构的,而两个这样的循环同构的矩阵的乘积依然是循环同构的,所以在用二分矩阵的方法计算的时候,可以先用O(N^2)的时间计算出第一行,再用O(N^2)的时间平移出下面各行的结果,这样每次做乘法的复杂度就由O(N^3)减少到了O(N^2)。
②矩阵乘法的multiply的函数最好使用引用传递传参,如果直接传参的话每次相当于把矩阵复制一遍,这样效率就比较低了。
#include<stdio.h> #include<string.h> #define MAXD 110 int N, M, L, R, D, a[MAXD]; struct Matrix { int a[MAXD][MAXD]; Matrix() { memset(a, 0, sizeof(a)); } void init() { int i, j; for(i = 0; i < N; i ++) a[i][(i + N - 1) % N] = L, a[i][i] = 1, a[i][(i + 1) % N] = R; } }; Matrix multiply(Matrix &x, Matrix &y) { int i, j, k; Matrix z; for(k = 0; k < N; k ++) if(x.a[0][k]) { for(j = 0; j < N; j ++) if(y.a[k][j]) z.a[0][j] = (z.a[0][j] + (long long)x.a[0][k] * y.a[k][j]) % D; } for(i = 1; i < N; i ++) { z.a[i][0] = z.a[i - 1][N - 1]; for(j = 1; j < N; j ++) z.a[i][j] = z.a[i - 1][j - 1]; } return z; } Matrix powmod(Matrix unit, Matrix mat, int n) { while(n) { if(n & 1) unit = multiply(mat, unit); n >>= 1; mat = multiply(mat, mat); } return unit; } void solve() { int i, j, ans; Matrix unit, mat; scanf("%d%d%d%d%d", &N, &M, &R, &L, &D); for(i = 0; i < N; i ++) { scanf("%d", &a[i]); unit.a[i][i] = 1; } mat.init(); unit = powmod(unit, mat, M); for(i = 0; i < N; i ++) { ans = 0; for(j = 0; j < N; j ++) if(unit.a[i][j] && a[j]) ans = (ans + (long long)unit.a[i][j] * a[j]) % D; if(i) printf(" "); printf("%d", ans); } printf("\n"); } int main() { int t; scanf("%d", &t); while(t --) { solve(); } return 0; }