格子刷油漆

X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如图1所示),现需要把这些格子刷上保护漆。

你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)

比如:a d b c e f 就是合格的刷漆顺序。

c e f d a b 是另一种合适的方案。

当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。

输入数据为一个正整数(不大于1000)

输出数据为一个正整数。

例如:

用户输入:

2

程序应该输出:

24

再例如:

用户输入:

3

程序应该输出:

96

再例如:

用户输入:

22

程序应该输出:

359635897

资源约定:

峰值内存消耗 < 64M

CPU消耗 < 1000ms

请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。

注意: main函数需要返回0

注意: 只使用ANSI C/ANSI C++ 标准,不要调用依赖于编译环境或操作系统的特殊函数。

注意: 所有依赖的函数必须明确地在源文件中 #include , 不能通过工程设置而省略常用头文件。

提交时,注意选择所期望的编译器类型(千万不要混淆c和cpp)。

动态规划,先设两个数组,rans[X]记录一共X列的格子,从左上角出发又回到第一列的情况,ans记录从左上角出发的所有情况,记住都是固定起点在左上角,即第一列的第一行。

对于rans的情况很好考虑,就是剩下的列,没列选一个格子,连接起来就是去的路线,回来时走剩下的格子即可。如图:

而对于所有的情况是多种多样的,路线不一定会回到第一列,终点在第几列就不好说了,我们可以根据起始的几步是如何走的来分情况:

第一步有三种情况:

三个方向都可以走,对于1来说下一步可以到第二列的两个格子中的一个,共两种情况,到了第二列又是新的起点,都是在角上,所以可以用ans[X - 1] * 2来表示;

对于2来说,下一步可以是回到第一列然后再去第二列,就转化成了X-2列的情况,而从第二列到第三列有两种情况用ans[X - 2] * 2来表示这种情况,也可以继续向右走,但是必须回到第二列,不然就无法刷第一列剩下的格子,这种情况是rans[X - 1];

对于3来说,下一步不能往下走,这样无法完成,所以它可以往右走,仍然要回到第二列,这种情况是rans[X - 1],也可以回到第一列,然后再去第二列,这种情况也是ans[X - 2] * 2。

所以固定第一列的走法以及固定前两列的走法,就可以由子问题转移,ans[X] = ans[X - 1] * 2 + ans[X - 2] * 4 + rans[X - 1] * 2;

这是对于X列的格子,从一个角出发的所有情况,那么起点不一定是从角出发,可以是从中间的格子设为第i列(i > 1 && i < n),这个时候也分三种情况:

很明显向下走是行不通的,左右阻隔了,无法完成,所以只能先往左然后回到这一列,再把右边的走完,或者反过来,以先往左为例,实际就是rans[i],这时回到了第i列,去往第i+1列有两种情况,而且这次不需要一定回到本列,所以是ans[n - i],而起点可以是第i列的两个格子中的一个,所以这种情况就是rans[i] * 2 * ans[n - i] * 2,反过来就是rans[n - i + 1] * 2 * ans[i - 1] * 2,最后的结果只需要求的中间所有列的情况的和加上四个角的情况即可。对于特殊情况只有一列此时是只有两个角,特殊对待。

代码:

#include <iostream>
#include <cstdio>
#include <sstream>
using namespace std;
typedef long long ll;
const int mod = 1000000007;
ll rans[1001],ans[1001];
int n;
int main() {
    scanf("%d",&n);
    rans[1] = ans[1] = 1;
    rans[2] = 2;
    ans[2] = 6;
    for(int i = 3;i <= n;i ++) {
        rans[i] = (rans[i - 1] * 2) % mod;
        ans[i] = (ans[i - 1] * 2 + ans[i - 2] * 4 + rans[i]) % mod;
    }
    ll sum;
    if(n == 1) sum = 2;
    else sum = ans[n] * 4;///四个角
    for(int i = 2;i < n;i ++) {
        sum = (sum + (rans[i] * 2 * ans[n - i] % mod + rans[n - i + 1] * 2 * ans[i - 1] % mod) * 2) % mod;
    }
    printf("%lld",sum);
}

猜你喜欢

转载自www.cnblogs.com/8023spz/p/10333412.html