题目
https://www.luogu.com.cn/problem/P3873
思路
线性递推,自然就是矩乘辣(话说省选竟然有这种裸题吗?)。
给个图意思一下吧(以n=5为例):
[left[ egin{matrix} w_1 & w_2 & w_3 & w_4 & w_5end{matrix}
ight]*left[ egin{matrix} 0 & 0 & 0 & 0 & a_5\1 & 0 & 0 & 0 & a_4\0 & 1 & 0 & 0 & a_3\0 & 0 & 1 & 0 & a_2\ 0 & 0 & 0 & 1 &a_1end{matrix}
ight]= left[ egin{matrix} w_2 & w_3 & w_4 & w_5 & w_6end{matrix}
ight]
]
那么要求第(m)项,把这个操作做(m-n)遍就可以了,此时答案矩阵的第1行第(n)列元素就是所求的(w_m)。
众所周知矩乘满足结合律,所以我们把中间的(n*n)矩阵拎出来,做个矩阵快速幂,再右乘上原来的(w)向量,就可以求出答案矩阵。
代码
#include<cstdlib>
#define maxn 110
#define mod 4147
using namespace std;
int w[maxn],a[maxn],n,m;
struct matrix{
int d[101][101];
public:
void init(){
int i,j;
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
d[i][j]=0;
}
matrix operator *(matrix x){
int i,j,k;
matrix ans;
ans.init();
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
for(k=1;k<=n;++k)
ans.d[i][j]=(ans.d[i][j]+d[i][k]*x.d[k][j])%mod;
return ans;
}
} e;
matrix pow(matrix x,int p){
matrix ans,base;
ans=e;base=x;
while(p){
if(p&1) ans=ans*base;
base=base*base;
p>>=1;
}
return ans;
}
int main(){
int i,j,ans;
matrix f,x;
scanf("%d%d",&n,&m);
for(i=n;i>=1;i--)
scanf("%d",&w[i]);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
x.init();f.init();e.init();
for(i=1;i<=n;i++)
e.d[i][i]=1;
for(i=1;i<=n;i++)
x.d[1][i]=w[i];
for(i=1;i<n;i++)
f.d[i+1][i]=1;
for(i=1;i<=n;i++)
f.d[i][n]=a[n+1-i];
ans=(x*pow(f,m-n)).d[1][n];
printf("%d",ans);
// system("pause");
return 0;
}