正题
题目链接:https://www.luogu.org/problemnew/show/P5004
题目大意
把NNN个无色格子排成一行,可以把某些格子染成黑色,但两个黑色格子之间必须至少有MMM个无色格子,求方案数
解题思路
首先很明显
fn=∑i=0n−m−1fif_n=\sum_{i=0}^{n-m-1}f_ifn=i=0∑n−m−1fi
然后我们发现∑i=0n−m−1fi\sum_{i=0}^{n-m-1}f_i∑i=0n−m−1fi就是前缀和,那我们在矩阵乘法中维护一个前缀和
A=[∑i=0n−m−1fifn−mfn−m+1...fn−1fn]A=\begin{bmatrix}\sum_{i=0}^{n-m-1}f_i \\ f_{n-m} \\ f_{n-m+1} \\ ... \\ f_{n-1} \\ f_{n} \end{bmatrix}A=⎣⎢⎢⎢⎢⎢⎢⎡∑i=0n−m−1fifn−mfn−m+1...fn−1fn⎦⎥⎥⎥⎥⎥⎥⎤
然后看着转移就好了。
codecodecode
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const ll Size=20,XJQ=1e9+7;
struct matrix{ll a[Size][Size];
}f;
ll n,m;
matrix operator *(matrix a,matrix b)
{matrix c;memset(c.a,0,sizeof(c.a));for(ll i=0;i<=m;i++)for(ll j=0;j<=m;j++)for(ll k=0;k<=m;k++)(c.a[i][j]+=a.a[i][k]*b.a[k][j]%XJQ)%=XJQ;return c;
}
matrix power(matrix f,ll b)
{b--;matrix ans;memset(ans.a,0,sizeof(ans.a));for(int i=0;i<=m;i++)ans.a[0][i]=1;ans.a[0][m]++;while(b){if(b&1) ans=ans*f;f=f*f;b>>=1;}return ans;
}
int main()
{scanf("%lld%lld",&n,&m);for(ll i=1;i<=m;i++)f.a[i][i-1]=1;f.a[0][m]=1;f.a[m][m]=1;f=power(f,n);printf("%lld",f.a[0][m]);
}