233 Matrix
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1471 Accepted Submission(s): 863
For each case, the first line contains two postive integers n,m(n ≤ 10,m ≤ 10 9). The second line contains n integers, a 1,0,a 2,0,...,a n,0(0 ≤ a i,0 < 2 31).
1 1 1 2 2 0 0 3 7 23 47 16
234 2799 72937Hint![]()
题意:
给你一个矩阵的第一行和第一列,让你求第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;
}