蓝桥杯 PREV-15 格子刷油漆(dp)

题目链接:

PREV-15 格子刷油漆

思路:

这个 2 n 2*n 的城墙,我们将四个端点和非端点分开考虑;
|-------------------------------------------------------------------------------------------------|
我们设 d p [ n ] dp[n] 为: n n 列时,从某一端点为起点,一共多少种刷漆方法;
从端点开始我们有:
(1)向上/下刷: 右边就变成 2 ( n 1 ) 2*(n-1) 的情况,而此时我们可以移到右边 2 ( n 1 ) 2*(n-1) 方格的 两个 端点,因此: d p [ n ] = d p [ n ] + 2 d p [ n 1 ] dp[n] = dp[n] + 2dp[n-1]
(2)向右刷一格,然后再往左刷第一列剩下的一格,然后再往右刷第二列剩下的一格: 右边变成 2 ( n 2 ) 2*(n-2) 的情况,而在第一次往右时有两个选择,在刷完 2 2 2*2 时往右又有两个选择,因此: d p [ n ] = d p [ n ] + 4 d p [ n 2 ] dp[n]=dp[n]+4dp[n-2]
(3)往右刷一格,之后再往右,最后回到第一列:此时在抵达右端点之前是不能回头或者刷同一列的,每次往右都有 2 2 个选择,一共选择 n 1 n-1 次,因此: d p [ n ] = d p [ n ] + 2 n 1 dp[n]=dp[n]+2^{n-1}
综上从端点开始刷的选项,递推式为: d p [ n ] = 2 d p [ n 1 ] + 4 d p [ n 2 ] + 2 n 1 ( n > 2 ) dp[n]=2dp[n-1]+4dp[n-2]+2^{n-1}\quad(n>2)
|-------------------------------------------------------------------------------------------------|
而从第 i ( 1 < i < n ) i(1<i<n) 列某个格子开始我们有:
(1)往左刷,然后再回到第 i i 列: 往左刷的步骤与上面的(3)相同,左边一共 2 i 1 2^{i-1} 种情况,此时右边变成 2 ( n i ) 2*(n-i) 的情况,而往右时有两个端点可以选,因此一共 2 i 1 2 d p [ n i ] 2^{i-1}*2*dp[n-i] 种方法;
(2)往右刷,然后再回到第 i i 列: 该方法与(1)互为镜像,因此一共 2 n i 2 d p [ i 1 ] 2^{n-i}*2*dp[i-1] 种方法;
我们知道每一列都有两个格子可以选,因此不从端点开始的选项一共有:
f ( n ) = 2 i = 2 n 1 ( 2 i 1 2 d p [ n i ] + 2 n i 2 d p [ i 1 ] ) f(n)=2*\sum\limits_{i=2}^{n-1}(2^{i-1}*2*dp[n-i]+2^{n-i}*2*dp[i-1]) 种方法;
|-------------------------------------------------------------------------------------------------|
四个端点皆可作为起点,因此最后的答案就是 4 d p [ n ] + f ( n ) 4*dp[n]+f(n)

代码:

#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;
}
发布了356 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45228537/article/details/104360208