【FZU 1911】Construct a Matrix(矩阵快速幂+找规律)
传送门:http://acm.fzu.edu.cn/problem.php?pid=1911
题意:数列fn为斐波那契数列,sn为fn的前n项和,设r=sn%m,求一个r*r的矩阵,矩阵元素只能为0,-1,1使得矩阵每行每列的和没有重复。
分析:我们知道fibonacci数列的前n项和S(n)=2*F(n)+F(n-1)-1,而本题中n的取值范围很大,所以求前n项和需要用矩阵快速幂。本题难点在于如何构造一个矩形满足题中条件。
首先我们分析一下,显然当r为0时,我们构造不出来这样一个矩阵,所以矩阵不存在;当r为1时,无论这个格子填什么数,他所在的行和列的和一定相同。
我们可以推广到r为奇数时,也必有一行和一列的和相等,所以当r==1||r&1时矩阵式不存在的。
当r为偶数,假设r==6,此时共有12个和,范围是-6~6,其中共有6个奇数,7个偶数。我们先把矩阵初始化为-1,可知,每将一个-1变为0,就会使两个偶数和变为奇数和(当任意两个0不同行或同列时),
所以至少要有3个不同行同列的-1变为0,才能使得和为6奇6偶。不妨假设现有矩阵为:
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
-1 -1 -1 -1 -1 -1
0 -1 -1 -1 -1 -1
-1 0 -1 -1 -1 -1
-1 -1 0 -1 -1 -1
接下来我们就要构造3个0所在的行和列,使他们的和分别等于6个不同的奇数:
-1 -1 -1
-1 -1 -1
-1 -1 -1
0 -1 -1 1 1 1
1 0 -1 1 1 1
1 1 0 1 1 1
这样,对于剩余的右上角的9个元素,我们只要填1和-1使得剩下的行和列的和为7个偶数中的任意6个即可(对称构造即可):
-1 -1 -1 -1 -1 1
-1 -1 -1 -1 1 1
-1 -1 -1 1 1 1
0 -1 -1 1 1 1
1 0 -1 1 1 1
1 1 0 1 1 1
这样,一个满足条件的矩阵就构造出来了。
总结:本题也属于思维大于算法和代码的题,难点在于如何去构造矩阵。
代码如下:
///BY: Torrance_ZHANG #include <stdio.h> #include <iostream> #include <string.h> #include <math.h> #include <algorithm> #include <stack> #include <queue> #include <set> #include <map> using namespace std; int m, n; struct Matrix { int a[2][2]; Matrix() { for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) a[i][j] = 0; } Matrix operator*(Matrix &p) { Matrix res; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { res.a[i][j] = 0; for (int k = 0; k < 2; k++) { res.a[i][j] += (a[i][k] * p.a[k][j] % m); } res.a[i][j] %= m; } } return res; } } init, unit; void init_Matrix() { init.a[0][0] = 1; init.a[0][1] = 0; init.a[1][0] = 0; init.a[1][1] = 1; unit.a[0][0] = 1; unit.a[0][1] = 1; unit.a[1][0] = 1; unit.a[1][1] = 0; } Matrix Pow(Matrix x, Matrix y, int k) { while (k) { if (k & 1) y = y * x; x = x * x; k >>= 1; } return y; } void solve(int r) { printf("Yes "); int ans[205][205]; memset(ans, -1, sizeof(ans)); for (int i = r / 2 + 1; i <= r; i++) ans[i][i - (r / 2)] = 0; for (int i = r / 2 + 2; i <= r; i++) for (int j = 1; j <= (i - r / 2 - 1); j++) ans[i][j] = 1; for (int i = r / 2 + 1; i <= r; i++) for (int j = r - i + 1; j <= r; j++) ans[j][i] = 1; for (int i = 1; i <= r; i++) { for (int j = 1; j <= r; j++) { printf("%d", ans[i][j]); printf(j == r ? " " : " "); } } } int main() { int t, cas = 1; scanf("%d", &t); while (t--) { init_Matrix(); scanf("%d%d", &n, &m); printf("Case %d: ", cas++); Matrix tmp = Pow(unit, init, n); //cout<<tmp.a[0][0]<<" "<<tmp.a[0][1]<<" "<<tmp.a[1][1]<<endl; int r = (tmp.a[0][1] * 2 + tmp.a[1][1] - 1) % m; //cout<<r<<endl; if (r == 0 || r & 1) { printf("No "); continue; } else solve(r); } }