[SNOI2017]礼物

题目

这题太傻了,众所周知二项式定理

\[(x+1)^n=\sum_{k=0}^n\binom{n}{k}x^k \]

于是把这个组合数放到矩阵里转移就好了

由于矩阵长得很特殊接近一个下三角,于是可以魔改一波优化常数

代码

#include<cstdio>
#define re register
const int mod=1e9+7;
struct mat {int a[15][15];}S,a;
long long n;int k,sz; 
int c[15][15];
inline mat operator*(mat a,mat b) {
	mat c;
	for(re int i=0;i<sz;i++)
		for(re int j=0;j<sz;j++)
			c.a[i][j]=0;
	for(re int i=0;i<=k;i++)
		for(re int j=0;j<=i;j++)
			for(re int t=0;t<=i;t++) 
				c.a[i][j]=(c.a[i][j]+1ll*a.a[i][t]*b.a[t][j]%mod)%mod;
	for(re int i=k+1;i<sz;i++)
		for(re int j=0;j<sz;j++) {
			if(j==k+1) continue;
			for(re int t=0;t<sz;t++)
				c.a[i][j]=(c.a[i][j]+1ll*a.a[i][t]*b.a[t][j]%mod)%mod;
		}
	return c;
}
int main() {
	scanf("%lld%d",&n,&k);
	for(re int i=0;i<=k;i++) c[i][0]=c[i][i]=1;
	for(re int i=2;i<=k;i++)
		for(re int j=1;j<i;j++)
			c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
	sz=k+3;
	for(re int i=0;i<=k;i++)
		for(re int j=0;j<=i;j++)
			a.a[i][j]=c[i][j];
	for(re int j=0;j<=k;j++)
		a.a[k+1][j]=a.a[k+2][j]=c[k][j];
	a.a[k+1][k+2]=1;a.a[k+2][k+2]=2;
	S=a;n--;
	while(n) {if(n&1ll) S=S*a;n>>=1ll;a=a*a;}
	printf("%d\n",S.a[k+1][0]);
	return 0;
}

posted @ 2019-05-11 11:03  asuldb  阅读(217)  评论(0编辑  收藏  举报