题解:P2768 珍珠项链
思路
首先可以想出,设 \(f_{i,j}\) 表示构造一个长度为 \(i\) 的序列,使用过 \(j\) 中珍珠的方案总数。容易得到:
\[\left\{\begin{matrix}
f_{i+1,j} \gets j\times f_{i,j}
\\
f_{i+1,j+1} \gets (k-j)\times f_{i,j}
\end{matrix}\right.
\]
时间复杂度为 \(O(Tnk)\),明显不能过,观察数据范围,考虑优化 \(O(n)\) 的部分。
对于每个 \(f_{i,j}\),只由 \(f_{i-1,j}\) 和 \(f_{i-1,j-1}\) 转移而来,可以使用矩阵加速。
观察答案为 \(\sum_{i=1}^{n}f_{i,k}\),可以在矩阵最后在加一行记录总和。
于是这题就能用 \(O(Tk^3 \log n)\) 过了。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+10,K=40,mod=1234567891;
int n,k;
struct Matrix{
int R,C;
int v[K][K];
};
Matrix operator *(Matrix& x,Matrix& y){
Matrix c;
c.R=x.R;
c.C=y.C;
memset(c.v,0,sizeof(c.v));
for(int i=0;i<x.R;i++){
for(int j=0;j<y.C;j++){
for(int k=0;k<x.C;k++){
c.v[i][j]=(c.v[i][j]+x.v[i][k]*y.v[k][j])%mod;
}
}
}
return c;
}
Matrix One(int x){
Matrix o;
o.R=x;
o.C=x;
for(int i=0;i<x;i++){
for(int j=0;j<x;j++){
o.v[i][j]=0;
if(i==j) o.v[i][j]=1;
}
}
return o;
}
Matrix qpow(Matrix x,int b){
Matrix ans=One(x.R);
while(b){
if(b&1) ans=ans*x;
x=x*x;
b>>=1;
}
return ans;
}
signed main(){
int _;
cin>>_;
while(_--){
cin>>n>>k;
Matrix a;
a.R=a.C=k+2;
memset(a.v,0,sizeof(a.v));
for(int i=1;i<=k;i++){
a.v[i][i]=i;
a.v[i][i-1]=k-i+1;
}
a.v[k+1][k-1]=1;
a.v[k+1][k]=k;
a.v[k+1][k+1]=1;
a=qpow(a,n);
Matrix ans;
memset(ans.v,0,sizeof(ans.v));
ans.R=k+2;ans.C=1;
ans.v[0][0]=1;
ans=a*ans;
cout<<ans.v[k+1][0]<<"\n";
}
return 0;
}

浙公网安备 33010602011771号