P1990-覆盖墙壁[详细介绍递推公式由来]

在这里插入图片描述

分情况:
{ 条形(刚好填满) { 横着 竖着 L 形(凸出一块) \left\{ \begin{aligned} & 条形(刚好填满) \left\{ \begin{aligned} 横着\\ 竖着\\ \end{aligned}\right. \\ & L形(凸出一块)\\ \end{aligned} \right. 条形(刚好填满){横着竖着L形(凸出一块)

条形

F ( n ) F(n) F(n) 长度为 n n n 的方法数

横着

F ( n ) + = F ( n − 1 ) F(n)+=F(n-1) F(n)+=F(n1)

竖着

F ( n ) + = F ( n − 2 ) F(n)+=F(n-2) F(n)+=F(n2)

L形

G ( n ) G(n) G(n) 为第 n n n 处多出来一块的方案数

G ( n ) = G ( n − 1 ) + F ( n − 2 ) G(n)=G(n-1)+F(n-2) G(n)=G(n1)+F(n2)

此为 G G G 的递推公式

答案

F ( n ) = F ( n − 1 ) + F ( n − 2 ) + 2 × G ( n − 1 ) F(n)=F(n-1)+F(n-2)+2\times G(n-1) F(n)=F(n1)+F(n2)+2×G(n1)

此为 F F F 的递推公式

初始条件

F ( 0 ) = 1 F ( 1 ) = 1 F ( 2 ) = 2   G ( 1 ) = 0 G ( 2 ) = 1 G ( 3 ) = 1 G ( 4 ) = 3 F(0)=1\\ F(1)=1\\ F(2)=2\\\ \\ G(1)=0\\ G(2)=1\\ G(3)=1\\ G(4)=3\\ F(0)=1F(1)=1F(2)=2 G(1)=0G(2)=1G(3)=1G(4)=3

变式

G ( n ) − G ( n − 1 ) = F ( n − 2 ) G ( n − 1 ) − G ( n − 2 ) = F ( n − 3 ) ⋯ G ( 4 ) − G ( 3 ) = F ( 2 ) G ( 3 ) − G ( 2 ) = F ( 1 ) G ( 2 ) − G ( 1 ) = F ( 0 ) 累加得 G ( n ) = ∑ k = 0 n − 2 F ( k ) + G ( 1 ) G ( 1 ) = 0 G ( n ) = ∑ k = 0 n − 2 F ( k ) \begin{aligned} &G(n)-G(n-1)=F(n-2)\\ &G(n-1)-G(n-2)=F(n-3)\\ &\cdots\\ &G(4)-G(3)=F(2)\\ &G(3)-G(2)=F(1)\\ &G(2)-G(1)=F(0)\\ &累加得\\ &G(n)=\sum_{k=0}^{n-2} F(k)+G(1)\\ &G(1)=0\\ &G(n)=\sum_{k=0}^{n-2} F(k)\\ \end{aligned} G(n)G(n1)=F(n2)G(n1)G(n2)=F(n3)G(4)G(3)=F(2)G(3)G(2)=F(1)G(2)G(1)=F(0)累加得G(n)=k=0n2F(k)+G(1)G(1)=0G(n)=k=0n2F(k)

所以 F ( n ) F(n) F(n)

F ( n ) = F ( n − 1 ) + F ( n − 2 ) + 2 × G ( n − 1 ) 带入 G ( n − 1 ) 得到 F ( n ) = F ( i − 1 ) + F ( i − 2 ) + 2 × ∑ i = 0 n − 3 F ( i ) \begin{aligned} &F(n)=F(n-1)+F(n-2)+2\times G(n-1)\\ &带入G(n-1)\\ &得到F(n)=F(i-1)+F(i-2)+2\times\sum_{i=0}^{n-3} F(i)\\ \end{aligned} F(n)=F(n1)+F(n2)+2×G(n1)带入G(n1)得到F(n)=F(i1)+F(i2)+2×i=0n3F(i)

代码

#include<iostream>
using namespace std;
const int N = 1e7+9;
int F[N];
int main() {
	int n; cin >> n;
	int ch = 0;
	F[0] = 1; F[1] = 1; F[2] = 2;
	for (int i = 3; i <= n; i++) {
		ch += F[i - 3];
		ch %= 10000;
		F[i] = F[i - 1] + F[i - 2] + 2 * ch;
		F[i] %= 10000;
	}
	cout << F[n];
	return 0;
}

或者改为

#include<iostream>
using namespace std;
const int N = 1e7 + 9;
int F[N];
int main() {
	int n; cin >> n;
	int ch = 0;
	F[3] = 1;\\表示n=0的时候
	for (int i = 4; i <= n+3; i++) {
		ch += F[i - 3];
		ch %= 10000;
		F[i] = F[i - 1] + F[i - 2] + 2 * ch;
		F[i] %= 10000;
	}
	cout << F[n+3];
	return 0;
}

由于只用到了 F ( i ) F(i) F(i) F ( i − 1 ) F(i-1) F(i1) F ( i − 2 ) F(i-2) F(i2) F ( 3 ) F(3) F(3)

简化为

#include<iostream>
using namespace std;
int main() {
	int n; cin >> n;
	int ch = 0;
	int a = 0, b = 0, c = 1,ans=0;
	for (int i = 1; i <= n; i++) {
		ch += a;
		ch %= 10000;
		ans = b + c + 2 * ch;
		ans %= 10000;
		a = b;
		b = c;
		c = ans;
	}
	cout << ans;
	return 0;
}

a a a 表示 F [ − 2 ] F[-2] F[2]

b b b 表示 F [ − 1 ] F[-1] F[1]

c c c 表示 F [ 0 ] F[0] F[0]

a n s ans ans 表示 F [ 1 ] F[1] F[1]

  • 29
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值