luoguP2768: 珍珠项链(矩阵乘法优化DP)
题意:有K种珍珠,每种N颗,求长度为1~N的项链,包含K种珍珠的项链种类数。N<=1e9, K<=30;
思路:矩阵快速幂,加个1累加前缀和即可。
#include<bits/stdc++.h> #define ll long long #define rep(i,w,v) for(int i=w;i<=v;i++) using namespace std; const int Mod=1234567891; struct mat{ ll a[32][32];int len; mat(){ rep(i,0,31) rep(j,0,31) a[i][j]=0; } mat friend operator *(mat m,mat n) { mat res; res.len=m.len; rep(k,0,res.len) rep(i,0,m.len) rep(j,0,n.len) { (res.a[i][j]+=1LL*m.a[i][k]*n.a[k][j]%Mod)%=Mod; } return res; } mat friend operator ^(mat m,int K){ mat res; res.len=m.len; rep(i,1,res.len) res.a[i][i]=1; while(K){ if(K&1) res=res*m; m=m*m; K>>=1; } return res; } }; int main() { int T,N,K; scanf("%lld",&T); while(T--){ scanf("%d%d",&N,&K); mat base,a,res; base.len=K+1; a.len=K+1; res.len=K+1; a.a[0][0]=1; base.a[K+1][K]=1; base.a[K+1][K+1]=1; rep(i,1,K){ base.a[i][i]=i, base.a[i][i-1]=K-i+1; } res=(base^(N+1))*a; printf("%lld\n",res.a[K+1][0]); } return 0; }
It is your time to fight!