有n个格子,从入口出发(注意,入口不是第一个格子,要另外计算),需要走到最后一个格子(即出口,第n个格子)。每走一步可选择走过1~k个格子,求能走到出口的方案数。
这道题的主体算法是递推,但是需要矩阵乘法优化。递推公式很简单,就是f[0]=1,f[i]=f[i-1]+f[i-2]+…+f[i-k],看到这种题,应马上想到矩阵优化,因为每次递推的公式是不变的。我们可以先求出f[1],f[2]…,f[k],把它作为初始序列(竖着),然后把公式转换为矩阵,举个例子,k=5的情况, 看图片,那么图片中的第一个矩阵就为半成品结果矩阵,我们就知道了半成品结果矩阵的规律就为它是一个k行k列的矩阵,a[i][i+1]=1(1<=i,k>i),a[k][i]=1(1<=i<=k),其余都为0。之后,把这个半成品结果矩阵平方(n-k)次(因为f[1],f[2]…,f[k]已经求出来了),变成结果矩阵。最后,用结果矩阵乘初始序列,得到结果序列,输出结果序列中的a[k][1],这题便解决了。
#include<cstdio>
#include<cstring>
using namespace std;
struct node
{
long long a[11][11];
node()
{
memset(a,0,sizeof(a));
}
};
int n;int he[11];
node pre,ans,f;
node chengfa1(node a,node b)
{
node c;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%7777777;
}
}
}
return c;
}
node chengfa2(node a,node b)
{
node c;
for(int i=1;i<=n;i++)
{
for(int k=1;k<=n;k++)
{
c.a[i][1]=(c.a[i][1]+a.a[i][k]*b.a[k][1])%7777777;
}
}
return c;
}
int main()
{
long long x;
scanf("%d%lld",&n,&x); //n为k,x为n
memset(he,0,sizeof(he));
he[0]=1;
for(int i=1;i<=n;i++)//求出f[1],f[2]...,f[k]
{
for(int j=1;j<=i;j++)
{
he[i]+=he[i-j];
}
}
if(x<=n){printf("%d\n",he[x]);return 0;}
x-=n;
for(int i=1;i<=n;i++)f.a[i][1]=he[i];
for(int i=1;i<n;i++)pre.a[i][i+1]=1;
for(int i=1;i<=n;i++)pre.a[n][i]=1;
for(int i=1;i<=n;i++)ans.a[i][i]=1;
while(x>0)
{
if(x%2==1)ans=chengfa1(pre,ans);
pre=chengfa1(pre,pre);
x/=2;
}
f=chengfa2(ans,f);
printf("%lld\n",f.a[n][1]%7777777);
return 0;
}