问题
参考博客
参考博客
X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如下图所示),现需要把这些格子刷上保护漆。
你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
比如:a d b c e f 就是合格的刷漆顺序。
c e f d a b 是另一种合适的方案。
当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
动态规划:
我们分为两种(假如a[i]表示2*i的格子从刷完所有格子的方案数(其中i表示列数,1<=i<=N))
- 从边角出发
- 从任意一个角出发(假设先从左上角出发,把结果*4就能得到四个角情况了)
- 第一种情况先把第一列刷完,再刷第二列,这样第一列到第二列有两个选择(要么对角,要么不是对角),记c[i]为从i-1跑到i列的情况数,那么c[i] = a[i-1]*2,然后剩下的格子又是一个全新的子问题
- 第二种情况,不先刷左下角,那么第二次就会刷第二列,这里又分成两种情况:
第1,任意刷第二列的一个,然后回到第一列刷完,再回到第二列,然后下一列
从上面可以看出,去到第三列可以有四种方法,记这种走到i列的为e[i],则e[i] = 4*a[i-2],然后剩下又是一个全新的子问题
第2,刷第二列的任意一个,然后不回到第一列,继续刷第三列的任意一个,这样只能不断往下走,不到尽头,不能返回
可以看出,每一次走往下一列,都有两种选择,记走到第i列为d[i],则d[i] = 2^i,d[i] = d[i-1]*2
那么四个角的所有情况为 4*(a[i] = 2 * a[i - 1] + 4 * a[i - 2] + b[i] )
- 从中间出发
起点在i那么两种情况
- 向左运动后回到第i列然后向右运动
- 向右运动后回到第i列然后向左运动
代码:(待补)
private static void paintWalls(int n) {
long[] d = new long[n + 1];
long[] a = new long [n + 1];
d[1] = 1;
d[2] = 2;
//a[n]表示起点为某一角落长度为n终点任意的情况数
a[1] = 1;
a[2] = 6;
for (int i = 3; i <= n; i++) {
d[i] = (2 * d[i - 1]) % MOD;
a[i] = (2 * a[i - 1] + d[i] + 4 * a[i - 2]) % MOD;
}
long ans = 4*a[n];
for (int i=2;i<n;i++){
ans = (ans + 8*a[i-1]*d[n-i])%MOD;
ans = (ans + 8*a[n-i]*d[i-1])%MOD;
}
if (n == 1){
System.out.println(2);
return;
}
if (n == 2){
System.out.println(24);
return;
}
System.out.println(ans);
}