格子刷油漆【动态规划问题】—NYOJ 980
个人博客页:https://www.scriptboy.cn/198.html
出处:蓝桥杯
题目描述:
X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆。
你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
比如:a d b c e f 就是合格的刷漆顺序。
c e f d a b 是另一种合适的方案。
当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
输入:
输入数据为一个正整数(不大于1000)
输出:
输出数据为一个正整数。
样例输入:
|
2
3
22
|
样例输出:
|
24
96
359635897
|
思路:
固定起点,由于如果起点在中间(第2~N-1列)可以分为左右两边来讨论,这时起点都是角格子。假如
a[i]
表示2*i
的格子从左上角开始刷刷完所有格子的方案数(其中i表示列数,1<=i<=N
),有三种刷法刷完所有格子:
- 先向下刷(即先刷左下角),向下刷完之后有两种方法跳到下一列,刷完剩下的
i-1
列需要2*a[i-1]
;- 向下一列刷,最后刷左下角,可以看出不能同列刷,只能一直向右刷,且在没有到最后一列之前是不能返回,所以刷完所有格子有2^i个方案;(此种情况比较特殊,后面需要还要用到,所以单独用
b[i]
存储下来)- 向下一列刷,有两种方案到下一列,然后返回左下角,再刷下一列未刷格子之后,然后有两种方案再到下一列,可见有四种方案到下下列,所以刷完所有格子有
4*a[i-2]
个方案;总之,就是左下角格子什么时候刷,造成了不同的情况。如果是起点不在角格子上,不难看出,可以将左右两侧分割成
2*i
和2*(N-i)
的矩形,需要其中一个矩形使用第2种刷法刷才能回到另一个矩形中。参考:https://blog.csdn.net/roosevelty/article/details/50706322
AC代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
#include <bits/stdc++.h>
#define mod 1000000007
using namespace std;
long long a[1005], b[1005], sum;
int main()
{
int N;
while(cin >> N)
{
sum = 0;
b[1] = 1;
for(int i = 2; i <= N; i++)
{
b[i] = b[i-1] * 2 % mod;
}
a[1] = 1;
a[2] = 6;
for(int i = 3; i <= N; i++)
{
a[i] = b[i] + a[i-2]*4 + a[i-1]*2;
a[i] %= mod;
}
sum += 4*a[N]; // 四个角的情况
// 中间为起点的情况
for(int i = 2; i < N; i++)
{
sum += (2*b[i]*2*a[N-i]+2*a[i-1]*2*b[N-i+1])%mod;
}
if(N == 1) sum = 2;
cout << sum %mod << endl;
}
return 0;
}
|
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?