题解: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;
}
posted @ 2025-08-30 17:42  幻琳  阅读(7)  评论(0)    收藏  举报