题目描述
X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆。
你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
比如:a d b c e f 就是合格的刷漆顺序。
c e f d a b 是另一种合适的方案。
当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
输入
输入数据为一个正整数(不大于1000)
输出
输出数据为一个正整数。
样例输入
3
样例输出
96
题意: 有一个2*n的矩形,每次可以往相邻格子移动,也可以对角移动,要求不能重复经过格子,求从任意格子出发的不同路径数。
分析: 设一下状态数组dp[i][0]和dp[i][1],dp[i][0]表示长度为i的格子,从左上角出发遍历全部格子然后返回起点上或下面点的方案数,dp[i][1]表示长度为i的格子,从左上角出发遍历全部格子然后到任意终点的方案数。对于dp[i][0]从图中可以看出从第i列到第i+1列共有两种方式,因此dp[i][0] = 2*dp[i-1][0]。
对于dp[i][1]的求解会比较复杂,首先可以按照第一步的不同把情况分为三类,如下图所示:
之后可以发现可以用前两列路线的不同情况来求出对应的路径数,这个过程需要自己画图多分析一下,这样最终得到dp[i][1] = 4*dp[i-2][1]+2*dp[i-1][0]+2*dp[i-1][1]。
在得到dp数组后就可以统计答案了,首先起点可能是四个角落,这样的路径数是4*dp[n][1],剩下的情况如下图:
剩下的起点就是在第2~n-1列上,对于确定的一列,起点可以在上面也可以在下面,所以最后路径数要乘2。再看一下起点在上面时的路径数,此时可以先往左走或者先往右走,不管哪种走法都需要先把单侧点遍历完然后到达起点下方点,之后再向另一侧走,这里有两种方向,所以要乘2。
综合一下最终的路径数就是4*dp[n][1]+sum(4*dp[i][0]*dp[n-i][1]+4*dp[n-i+1][0]*dp[i-1][1]),i∈[2, n-1]。
具体代码如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#define int long long
#define mod 1000000007
using namespace std;
int n, dp[1005][2];
//dp[i][0]表示长度为i的格子,从左上角出发遍历全部格子然后返回起点上或下面点的方案数
//dp[i][1]表示长度为i的格子,从左上角出发遍历全部格子然后到任意终点的方案数
signed main()
{
cin >> n;
dp[1][0] = 1, dp[2][0] = 2;
dp[1][1] = 1, dp[2][1] = 6;
for(int i = 3; i <= n; i++)
{
dp[i][0] = dp[i-1][0]*2%mod;
dp[i][1] = (4*dp[i-2][1]%mod+2*dp[i-1][1]%mod+2*dp[i-1][0]%mod)%mod;
}
int ans = 4*dp[n][1]%mod;//四个角落为起点的方案数
for(int i = 2; i <= n-1; i++)
ans = (ans+4*dp[i][0]*dp[n-i][1]%mod+4*dp[n-i+1][0]*dp[i-1][1]%mod)%mod;
cout << ans;
return 0;
}