蓝桥杯 格子刷油漆

题目(2013 B组决赛第5题):
    X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如图1所示),现需要把这些格子刷上保护漆。
    你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
    比如:a d b c e f 就是合格的刷漆顺序。
    c e f d a b 是另一种合适的方案。
    当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
    输入数据为一个正整数(不大于1000)
    输出数据为一个正整数。
例如:
用户输入:
2
程序应该输出:
24
再例如:
用户输入:
3
程序应该输出:
96
再例如:
用户输入:
22
程序应该输出:
359635897
资源约定:
峰值内存消耗 < 64M

CPU消耗  < 1000ms




思路:这道是个递推题。暴力搜索复杂度太高,指数级别的。这个公式推了好久,因为情况比较多。2*N的出发的起点格子一共有2种类型。

1、四个角。设b[n]表示边缘一列的一个角的格子出发,遍历全体格子后,结束点再该列的种类数  b[1]=1  b[n]=b[n-1]*2 ,a[n]表示长度为n的一个角的格子出发,遍历全体格子的种类数 : a[1]=1   a[2]=6  a[n]=2*a[n-1]+4*a[n-2]+b[n]  (n>2) +2*a[n-1]表示如果第二个涂油漆的点和出发点是同一列。+4*a[n-2]表示和出发点是同一列的格子是第三次涂的,它要先经过前一列周转之后才涂,涂完之后前一列也就涂完了,就剩下n-2列没有涂,乘以4是因为第二次涂的格子有2种,然后开始从n-2列开始涂的时候又有两个选择,根据乘法原理2*2. 。 +b[n] 表示和出发点是同一列的格子是最后一次才涂的。

2、除了四个角的其余格子。设 c[i]表示从中间(1<i<n)的某一列出发, 遍历全体格子的种类数  c[i]=2*b[i]*2*a[n-i]+2*b[n-i+1]*2*a[i-1]  加号左边表示县遍历左边的格子,加号右边的式子表示先遍历右边的格子 ,因为先出发的那一边必须回到出发的那一列,而往后就是不收限制即a[n]的情况了 。

结果的答案就是 num=4*a[n]+sum(c[i]) 1<i<n


代码:

#include<iostream>
#include <string.h>
#include<memory>

const int MOD =1000000007; 

using namespace std;

// a[n]表示最边缘一列的一个角的格子出发,遍历全体格子的种类数   a[1]=1   a[2]=6  a[n]=2a[n-1]+4a[n-2]+b[n]  n>2
// b[n]表示边缘一列的一个角的格子出发,遍历全体格子后,结束点再该列的种类数  b[1]=1  b[n]=b[n-1]*2 
// c[i]表示从中间的格子出发, 遍历全体格子的种类数  c[i]=2*b[i]*2*a[n-i]+2*b[n-i+1]*2*a[i-1]  加号左边表示县遍历左边的格子,加号右边的式子表示先遍历右边的格子 ,因为先出发的那一边必须回到出发的那一列,而往后就是不收限制即a[n]的情况了 
long long a[1010]={0};
long long b[1010]={0};
long long c[1010]={0};
int main()
{

	int n;
	long long num=0;
	a[1]=1;
	a[2]=6;
	b[1]=1;
	b[2]=2;
	cin>>n;

	for(int i=3;i<=n;i++)
	{
		b[i]=b[i-1]*2%MOD;
		a[i]=((2*a[i-1])%MOD+(4*a[i-2])%MOD+b[i]%MOD)%MOD;
	}
	for(int i=2;i<=n;i++)
	{
		c[i]=4*((b[i]*a[n-i])%MOD+(b[n-i+1]*a[i-1])%MOD)%MOD;
	}
	num=4*a[n]%MOD;
	for(int i=2;i<n;i++)
	{
		num+=(c[i]%MOD);
		num%=MOD;
	}
	
	cout<<num<<endl;
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值