题意
给出矩阵的第0行(233,2333,23333,...)和第0列a1,a2,...an(n<=10,m<=10^9),给出式子: A[i][j] = A[i-1][j] + A[i][j-1],要求A[n][m]。
分析
推单位矩阵,先开始没想出来,于是看了题解,但是没有看懂,只有又自己推,然后发现就推出来了诶
不要把菜当做不思考的借口
第0列是告诉了的,忽略,从第1列开始看,第一列是
233
a1
a2
a3
a4
...
an
观察到第二列是2333,会出现一个3,于是我们干脆在每一列后面补一个3方便递推
于是第一列和第二列分别是
233 2333
a1 2333+a1
a2 2333+a1+a2
a3 2333+a1+a2+a3
a4 2333+a1+a2+a3+a4
... ...
an 2333+a1+a2+...+an-1+an
3 3
想从第一列得到第二列,那需要乘什么呢?肯定是个n+2行n+2列的矩阵
直接推发现2333=233*10+3
于是第一行10 0 0 ...0 0 1
2333+a1=233*10+3+a1
于是第二行 10 1 0 ... 0 0 1
类推可得到单位矩阵
10 0 0 ...0 0 1
10 1 0 ...0 0 1
10 1 1 ...0 0 1
10 1 1 ...1 0 1
10 1 1 ...1 1 1
0 0 0 ... 0 0 1
将这个矩阵求m-1次方再与原来的第一列相乘,就可求出A[n][m],第1列用第0列推出
或者是直接用第0列,求m次方
代码
#include<bits/stdc++.h> using namespace std; #define N 15 #define ll long long #define mod 10000007 ll n,m,f; ll one[N]; struct email { ll x[N][N]; }a,ans; inline void init() { one[0]=23;one[n+1]=3; for(ll i=1;i<=n;i++)scanf("%lld",&one[i]); memset(a.x,0,sizeof(a.x)); for(ll i=0;i<=n;i++)a.x[i][0]=10,a.x[i][n+1]=1; a.x[n+1][n+1]=1; for(ll i=1;i<=n;i++) for(ll j=1;j<=i;j++) a.x[i][j]=1; } inline email mul(email a,email b) { email c; memset(c.x,0,sizeof(c.x)); for(ll i=0;i<=n+1;i++) for(ll j=0;j<=n+1;j++) for(ll k=0;k<=n+1;k++) c.x[i][j]+=a.x[i][k]*b.x[k][j],c.x[i][j]%=mod; return c; } inline email ksm(email a,ll m) { if(m==1)return a; email b=ksm(a,m/2); b=mul(b,b); if(m&1)b=mul(b,a); return b; } int main() { while(scanf("%lld%lld",&n,&m)==2) { init(); ans=ksm(a,m);f=0; for(ll i=0;i<=n+1;i++) f+=ans.x[n][i]*one[i],f%=mod; printf("%lld ",f); } return 0; }