【矩阵乘法】洛谷P5004 专心OI - 跳房子

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/88750708

D e s c r i p t i o n Description

从第一个格子跳到第 n n 个格子,每次至少跳 m + 1 m+1 格,求方案数

或者
n n 个无色格子排成一行,可以把某些格子染成黑色,但两个黑色格子之间必须至少有 m m 个无色格子,求方案数

n 1 0 18 , m 15 n\leq 10^{18},m\leq 15


S o l u t i o n Solution

首先第 i i 个格子显然可以从第
f [ i ] = j = 0 i m f [ j ] f[i]=\sum_{j=0}^{i-m}f[j]
然后方案数显然是 f [ n + m ] f[n+m] (因为可以跳出去)
然后就愉快 n 2 n^2

从染色的角度考虑,对于每个格子,不染色时方案书显然为 f [ i 1 ] f[i-1] ,染色的话则加上 f [ i m + 1 ] f[i-m+1] ,就得到了方程

f [ i ] = f [ i 1 ] + f [ i m + 1 ] f[i]=f[i-1]+f[i-m+1]
这样就愉快 O ( n ) O(n)

但是酱紫距离满分还是有很大差距滴

n 1 0 18 n\leq 10^{18} 想到了啥?,矩阵乘法!

愉快 l o g log AC


C o d e Code

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const LL WYC=1e9+7;
LL n;int m;
struct matrix
{
	LL a[18][18];
}x,ans;
matrix operator *(matrix a,matrix b) 
{
	matrix c;
	memset(&c,0,sizeof(c));
	for(register int i=0;i<=m;i++)
	 for(register int j=0;j<=m;j++)
	  for(register int k=0;k<=m;k++)
	   (c.a[i][j]+=a.a[i][k]*b.a[k][j])%=WYC;
	return c;
}
signed main()
{
	scanf("%lld%d",&n,&m);n--;
	x.a[m][m]=x.a[0][m]=1;
	for(register int i=0;i<=m;i++) ans.a[0][i]=i+2,x.a[i+1][i]=1;
	//初始化,前面m个格子的方案数显然为i+1,由于坐标从0开始所以是i+2
	//然后只有f[i]=f[i-1]+f[i-m-1]的,其它的f[i-k]=f[i-k]
	for(;n;n>>=1,x=x*x) 
	if(n&1) ans=ans*x;
	printf("%lld",ans.a[0][0]);
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/88750708