蓝桥杯 历届试题 格子刷油漆

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


  你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
  比如:a d b c e f 就是合格的刷漆顺序。
  c e f d a b 是另一种合适的方案。
  当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
输入格式
  输入数据为一个正整数(不大于1000)
输出格式
  输出数据为一个正整数。
样例输入
2
样例输出
24
样例输入
3
样例输出
96
样例输入
22
样例输出
359635897


【解题思路】

这题使用动态规划,状态转移方程比较复杂,找到了状态转移方程这题就轻松多了。

状态转移方程: b[i] = 2*b[i]

                         a[i] = 2*a[i-1] + b[i] + 2*2*a[i-2]

                         sum = 4*a[n]    sum = sum + 2*2*(b[i]*a[n-i] + b[n-i+1]*a[i-1])

解释一下状态转移方程,这道题目分两种情况,一种是4个顶点出发另一种就是从中间出发,假设一共有2*n个格子:

1、4个顶点出发,以一个顶点作为例子讲解 

      情况①,第一步走同一列的另一个格子,如图A→B,B就可以到C或者D,这种情况可以转换成a[i-1]

2*a[i-1]


      情况②,第一步走另一列最后回到同一列的另一个格子,如图A→C或者A→D,最后回到B,这种情况用数组b存储可以转化成b[i-1]

b[i] = 2*b[i-1]


      情况③,第一步走另一列再到同一列的另一个格子再到另一列,如图A→C→B→D或者A→D→B→C,C又可以到E或者F,D也可以到E或者F,这种情况就转换成a[i-2]

2*2*a[i-2]


    a[i] = 2*a[i-1] + b[i] + 2*2*a[i-2]

    所以4个顶点出发的方案数有 sum = 4 * a[n]

2、从中间开始经过同一列的另一个格子后到结尾,以i=3的E为例子讲解

    以i开始分割,左边ABCDEF可以看做以E为顶点的一组格子最后回到同一列的F,右边可以看做以G或者以H为顶点的一组格子,这样就有b[i]*a[n-i]*2种方案;同理右边EFGHIJ看做以E为顶点最后回到同一列F的一组格子,左边ABCD可以看做以C或者D为顶点的的一组格子,这样就有b[n-i+1]*a[i-1]*2种方案


    同理也可以F为开始的地方,那么从第i列开始刷漆的方法就有 2*(b[i]*a[n-i]*2 + b[n-i+1]*a[i-1]*2)中方案,也就是2*2*(b[i]*a[n-i] + b[n-i+1]*a[i-1])种方案

所以最终sum = sum + 2*2*(b[i]*a[n-i] + b[n-i+1]*a[i-1])

#include<iostream>
using namespace std;
const int Maxnum = 1000000007;
int main()
{
	//__int64是因为VC++6.0不支持long long , 蓝桥杯的时候可以改成long long
	__int64 a[1001];  //用于求顶点开始的方法数
	__int64 b[1001];  //用于求顶点开始回到同一列的方法数
	int sum;  //cout不支持__int64就改成int了
	int n,i;
	cin>>n;
	b[1] = 1;
	b[2] = 2;
	a[1] = 1;
	a[2] = 6;  //三种情况2+2+2
	for(i=3;i<=n;i++)
	{
		b[i] = (2*b[i-1])%Maxnum;  //边操作边取余
		a[i] = (2*a[i-1]+b[i]+2*2*a[i-2])%Maxnum;
	}
	sum = 4*a[n];  //4个顶点
	for(i=2;i<n;i++)  //求中间开始的方法数
		sum = (sum+2*2*(b[i]*a[n-i]+b[n-i+1]*a[i-1]))%Maxnum;
	cout<<sum<<endl;
	return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值