/*
标题:格子刷油漆
X国的一段古城墙的顶端可以看成 2*N个格子组成的矩形(如图1所示),现需要把这些格子刷上保护漆。
你可以从任意一个格子刷起,刷完一格,可以移动到和它相邻的格子(对角相邻也算数),但不能移动到较远的格子(因为油漆未干不能踩!)
比如:a d b c e f 就是合格的刷漆顺序。
c e f d a b 是另一种合适的方案。
当已知 N 时,求总的方案数。当N较大时,结果会迅速增大,请把结果对 1000000007 (十亿零七) 取模。
输入数据为一个正整数(不大于1000)
输出数据为一个正整数。
宽为2,长未知
例如:
用户输入:
2
程序应该输出:
24
再例如:
用户输入:
3
程序应该输出:
96
再例如:
用户输入:
22
程序应该输出:
359635897
*/
1.一开始暴力dfs的做,不加优化半个小时没有结果,优化需要考虑的比较多,
2.看了网上的题解,用dp去做,实际上dp的做法也就是优化的方向,或者记忆化递归应该也是可以的
#include <iostream>
#include <cstring>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
/*
思路:先说说思路吧,从题面上看,似乎是一道典型的搜索题,从数据上看,搜索肯定大大的超时,既然这样,要么优化,要么另辟蹊径,怎么优化呢,当然是要模拟
找规律,很显然的就是,如果从中间开始刷的话,那么不能一开始就把这一列给刷了,因为会导致过不去另一边,所以只能把一边给全部刷完后再回到起点列把剩下的格子
刷了,再去刷另一边的,只要不是两端的那两列,那么对于中间任意一列,这都是必须满足的,是不是很像动态规划的状态转移呢,那么如果从两端的两列开始刷呢,大致分为三种情况:
1.将该列刷完后再去刷下一列
2.最后才回来刷该列剩下的那一个,(和从中间开始刷的那种情况一样)
3. 先往前刷一列再回来把起点列的剩下那格刷了,再去下一列刷剩下的,再继续往前刷,就是两列两列的刷,那么有没有三列三列或者,往前刷几列再返回来刷呢,实际上这是不可行的
,可以简单的模拟一下就明白了。
*/
//思路大概就是上面的,从中间开始刷,实际上就是把城墙暂时分成了两部分,左边部分和右边部分,
const int mod=1e9+7;
long long a[1010],b[1010]; //a数组表示终点任意的情况,b数组表示终点是该列的另一格的情况(中间开始刷那种情况)
long long ans=0;
int n;
int main(int argc, char *argv[]) {
cin>>n;
a[1]=1;//为什么是1,不是2呢?请思考
b[1]=1;
b[2]=2;
a[2]=6;//为什么要初始化到2呢? 请思考
for(int i=3;i<=n;i++)
{
b[i]=(2*b[i-1])%mod;
a[i]=(2*a[i-1]+b[i]+2*2*a[i-2])%mod;
}
ans=(a[n]*4)%mod;//这里才考虑起点,因为从两端那两列的任意一个点开始都一样。
for(int i=2;i<n;i++)//表示从中间开始,乘法原理
{
ans=(ans+2*2*b[i-1]*2*a[n-i])%mod;//先往左走
ans=(ans+2*2*b[n-i]*2*a[i-1])%mod;//先往右走
}
cout<<ans<<endl;
return 0;
}