题意:
给你一个矩阵的第一行和第一列,让你求第n行第m列的值。其中矩阵中元素有递推式a[i][j] = a[i-1][j]+a[i][j-1]。其中第一行为0,233,2333,23333...,第一列为0,x1,x2,x3...,xi在输入中给出。n<=10,m<=10^9
分析:
一开始我还想通过递推关系找规律呢==,后来发现不是很好找,即使找到相应的东西也需要求10^9个元素的和。。。想想可以用矩阵快速幂解决,对于这种有着递推关系且数量较大的递推式来说,但始终想不到如何构造矩阵。。。后来看题解才知道,原来可以一列一列往右推构成递推关系。如果去掉第一行,我们很容易构造矩阵来将第一列推到第二列,而对于233到2333这些我们可以*10+3递推到,然后如果要合一起的话这里需要再增加一行才能实现233推到2333。首先第一行第一个数可以改为23这样更好满足*10+3的关系且并不会影响最终结果,然后我们再增加n+1这行,全是3,这样就很容易利用矩阵从一列推到另一列了。例如n=3,m=3的情况,可以构造矩阵:
233 10 0 0 0 1 23
x1+233 10 1 0 0 1 x1
x1+x2+233 = 10 1 1 0 1 * x2
x1+x2+x3+233 10 1 1 1 1 x3
3 0 0 0 0 0 3
code:
#include
#include
#include
#include
#include
#include
using namespace std;
const int mod = 1e7+7;
const int N = 1e5+10;
typedef long long ll;
#define INF 1<<30
int n, m;
struct Mat
{
ll mat[15][15];
};
Mat operator * (Mat a, Mat b)
{
Mat c;
memset(c.mat, 0, sizeof(c.mat));
for(int k=0; k= j && i != n+1) || j == n+1) a.mat[i][j] = 1;
else a.mat[i][j] = 0;
}
}
for(; m>0; m>>=1)
{
if(m & 1) res = res*a;
a = a*a;
}
ll x, ans = 23*res.mat[n][0];
for(int i=1; i<=n; i++)
{
scanf("%lld", &x);
ans = (ans+x*res.mat[n][i]%mod)%mod;
}
ans = (ans+3*res.mat[n][n+1]%mod)%mod;
printf("%lld\n", ans);
}
return 0;
}