积木块(动态规划+压缩空间)+(数学法)

前言:有这么一道动态规划的好题,我觉得值得纪念一下把他弄懂了
在这里插入图片描述

思路:
使用动态规划。由于N非常大,所以选择&来压缩空间。原理是:

奇数&1=1
偶数&1=0

我定义的dp是这样:

  1. dp[i][0]表示第i列格子的积木块为0
  2. dp[i][1]表示第i列的积木块数量是1,且当前列的下面一个格子是空的
  3. dp[i][2]表示第i列的积木块数量是1,且当前列的上面一个格子是空的
  4. dp[i][3]表示第i列的积木块数量是2,也就是第i列被填满。
#include<iostream>
#include<algorithm>
using namespace std;

const int mod=1e9+7;
long long int f[2][4];

int main()
{
	int n;
	cin>>n;
	f[1][0]=1;  //第一层没有格子,那么只有什么都不放一种情况
    f[1][1]=0;   //第一层不可能只有一个积木,因为L型积木至少两层才可以使用
	f[1][2]=0;  //同理;
	f[1][3]=1;   //第1层填满,就是放一个竖的积木
	for(int i=2;i<=n;i++)
	{
		f[i&1][0]=f[(i-1)&1][3];  //第i层没有积木,等价于第i-1层积木填满
		f[i&1][1]=(f[(i-1)&1][0]+f[(i-1)&1][2])%mod;   //第i层上面有积木,下面没有积木,等于:第i-1层没有积木的情况放一个L+第i-1层有一个L的情况放一个横条
		f[i&1][2]=(f[(i-1)&1][0]+f[(i-1)&1][1])%mod;  //同理
		f[i&1][3]=((f[(i-1)&1][3]+f[(i-1)&1][0])%mod+(f[(i-1)&1][1]+f[(i-1)&1][2])%mod)%mod;  //第i层填满的情况等于:(1)第i-1层填满 加一个竖条  
		//(2)第i-1层空的,加两个横条  (3)第i-1层上面一个格子+1个L  (4)第i-1层下面一个格子+1个L。
	}
	cout<<f[n&1][3]<<endl;
	return 0;
}

说实话,这道题不难,就是看了别人的题解把自己绕晕了,还没看懂。
然后有大神用一个递推方程写出一个更好的方法:

我来试写一次:

设f[n]为前n层填满的方案:
那么穷举一下所有的可能

  1. f[i]+=f[i-1] 即第i-1层是填满的,第i层加一个竖条
  2. f[i]+=f[i-2] 即第i-2层是填满的,然后加两个横条填满第i-1和第i层
  3. f[i]+=f[i-3]*2 第i-1层放了一个L,L可以有两种放法
  4. f[i]+=f[i-4]*2 第i-3层放一个L,然后i-2层接一个竖条
  5. f[i]+=f[i-5]2 …
    得出递推式:
    f[i]=2
    f[i-1]+f[i-3];
#include<iostream>
using namespace std;




const int mod=1e9+7,N=1e7+10;



long long int f[N];

int main()
{
    int n;
    cin>>n;
    f[0]=0;
    f[1]=1;
    f[2]=2;
    f[3]=5;
    for(int i=4;i<=n;i++)
    {
        f[i]=(2*f[i-1]+f[i-3])%mod;
        
    }
    
    cout<<f[n];
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值