1 1 1 2 2 0 0 3 7 23 47 16
题意:
给你一个矩阵的第一行和第一列,让你求第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<stdio.h> #include<string.h> #include<iostream> #include<string> #include<queue> #include<algorithm> 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<n+2; k++) for(int i=0; i<n+2; i++) for(int j=0; j<n+2; j++) c.mat[i][j] = (c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod; return c; } int main() { while(~scanf("%d%d", &n,&m)) { Mat res, a; for(int i=0; i<n+2; i++) for(int j=0; j<n+2; j++) res.mat[i][j] = (i==j); for(int i=0; i<n+2; i++) { for(int j=0; j<n+2; j++) { if(j == 0 && i != n+1) a.mat[i][j] = 10; else if((i >= 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; }