题目链接:
PREV-15 格子刷油漆
思路:
这个
的城墙,我们将四个端点和非端点分开考虑;
|-------------------------------------------------------------------------------------------------|
我们设
为:有
列时,从某一端点为起点,一共多少种刷漆方法;
从端点开始我们有:
(1)向上/下刷: 右边就变成
的情况,而此时我们可以移到右边
方格的 两个 端点,因此:
;
(2)向右刷一格,然后再往左刷第一列剩下的一格,然后再往右刷第二列剩下的一格: 右边变成
的情况,而在第一次往右时有两个选择,在刷完
时往右又有两个选择,因此:
;
(3)往右刷一格,之后再往右,最后回到第一列:此时在抵达右端点之前是不能回头或者刷同一列的,每次往右都有
个选择,一共选择
次,因此:
;
综上从端点开始刷的选项,递推式为:
|-------------------------------------------------------------------------------------------------|
而从第
列某个格子开始我们有:
(1)往左刷,然后再回到第
列: 往左刷的步骤与上面的(3)相同,左边一共
种情况,此时右边变成
的情况,而往右时有两个端点可以选,因此一共
种方法;
(2)往右刷,然后再回到第
列: 该方法与(1)互为镜像,因此一共
种方法;
我们知道每一列都有两个格子可以选,因此不从端点开始的选项一共有:
种方法;
|-------------------------------------------------------------------------------------------------|
四个端点皆可作为起点,因此最后的答案就是
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1005;
const ll mod = 1000000007;
ll dp[maxn];
inline ll pow_mod(ll a, int n) {
for(ll res = 1;; n >>= 1) {
if(!n) return res;
if(n & 1) res = (res * a) % mod;
a = (a * a) % mod;
}
}
int main() {
#ifdef MyTest
freopen("Sakura.txt", "r", stdin);
#endif
int n;
cin >> n;
dp[1] = 1, dp[2] = 6;
for(int i = 3; i <= n; i++) {
dp[i] = (2 * dp[i - 1] + pow_mod(2, i - 1) + 4 * dp[i - 2]) % mod;
}
ll ans = 0;
for(int i = 2; i < n; i++) {
ans = (ans + pow_mod(2, i) * dp[n - i] % mod + pow_mod(2, n - i + 1) * dp[i - 1] % mod) % mod;
}
cout << (2 * ans + 4 * dp[n]) % mod;
return 0;
}