题目的意思是有一个叫做233 Matrix的矩阵。
给定第一行元素a(0, 1) = 233, a(0, 2) = 2333, a(0, 3) = 23333, ..., a(0, n) = 10 * a(0, n - 1) + 3, (n >= 2)。
第一列元素a(1, 0), a(2, 0), a(3, 0), ..., a(n, 0),和一个递推式子a(i ,j) = a(i - 1, j) + a(i, j - 1), (
i,j ≠ 0),让你求出a(n, m) mod
10000007的值。
其中,a(0, 0)应该等于0,n和m及第一列元素由输入给定。数据范围为n ≤ 10,m ≤ 109
因为数据量很大,暴力求解肯定是不行的。必定超时,虽然给定的时间是5秒钟。
那接下来就是推公式了,而我最终也真的推出来个公式,但很遗憾,它只有当n和m相等的时候才成立,可是n最大才为10,这种思路也就被否定了。
既然给定的是一个矩阵的形式,难道可以用矩阵快速幂搞出来?可以试试。注意一点,如果能构造出来快速幂的话,也只有按列来推。
对于给定的递推式a(i ,j) = a(i - 1, j) + a(i, j - 1),将它展开则a(i, j) = a(i - 1, j) + a(i, j - 1) = a(i - 2, j) + a(i - 1, j - 1) + a(i, j - 1) = a(i - 3, j) + a(i - 2, j - 1) + a(i - 1, j - 1) + a(i, j - 1) = ...
很快就可以发现规律了得到:a(i, j) = a(1, j - 1) + a(2, j - 1) + ... + a(i, j - 1) + a(0, j)。
如下图:

图片橙色部分等于蓝色部分的和,也就是上边的公式。
我们的目的是由当前蓝色的部分,推出与它紧邻的右边下一列蓝色的部分。
构造如下矩阵,我们希望找出一个n+1阶的方阵,使得如下矩阵式成立。

根据上述推导的公式,可得A矩阵的第一行为[1 0 ... 0 1],
第二行为[1 1 0 ... 0 1],第三行为[1 1 1 0 ... 0 1],。。。,第n行为[1 1 1 ... 1 1]。
遗憾的是第n+1行无论怎么取值也无法是矩阵式成立。
因为a(0, m + 1) = a(0,m)* 10 + 3,那么显然n+1行的矩阵不能满足要求,可以将矩阵变成n+2行最后一行为3。则矩阵就变成:

相应的A矩阵第一行为
[1 0 ... 0 1 0],
第二行为[1 1 0 ... 0 1 0],第三行为[1 1 1 0 ... 0 1 0],。。。,第n行为[1 1 1 ... 1 1 0],
第n+1行为[0 0 0 0 .... 0 10 1],
第n+2行为[0 0 0 0 ... 0 0 1]。则矩阵A的形式如下:

由于矩阵乘法的结合律,可得:

这样就可以对矩阵A^m使用矩阵快速幂了。
自己的代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
const ll mod = 10000007;
int n, m;
struct matrix
{
ll mat[15][15];
matrix()
{
memset(mat, 0, sizeof(mat));
}
};
matrix multi(matrix A, matrix B)
{
matrix C;
for(int i = 1; i <= n+2; i++)
for(int j = 1; j <= n+2; j++)
for(int k = 1; k <= n+2; k++)
C.mat[i][j] = (C.mat[i][j] + A.mat[i][k]*B.mat[k][j]) % mod;
return C;
}
matrix fast_mod(matrix base, int k)
{
matrix tmp;
for(int i = 1; i <= n+2; i++)
tmp.mat[i][i] = 1;
while(k)
{
if(k&1)
tmp = multi(tmp, base);
base = multi(base, base);
k >>= 1;
}
return tmp;
}
int main()
{
while(scanf("%d%d", &n, &m) != EOF)
{
matrix ans, base;
ans.mat[1][1] = 23;
for(int i = 1; i <= n; i++)
scanf("%d", &ans.mat[i+1][1]);
ans.mat[n+2][1] = 3;
for(int i = 1; i <= n+1; i++)
base.mat[i][1] = 10;
for(int i = 1; i <= n+2; i++)
base.mat[i][n+2] = 1;
for(int i = 2; i <= n+1; i++)
for(int j = 2; j <= i; j++)
base.mat[i][j] = 1;
base = fast_mod(base, m);
ans = multi(base, ans);
cout << ans.mat[n+1][1] << endl;
}
return 0;
}