题目(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
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;
}