总时间限制:
20000ms
单个测试点时间限制:
1000ms
内存限制:
131072kB
描述
还是传统的走道铺砖问题,还是2行N列,现在给你三种砖,其规格分别为1*2,2*1,2*2。现在用这三种砖将走道铺满且砖与砖块之间不能重叠。问有多少种做法,值得注意的是:如果一种铺放的方法可以由另一个翻转过来得到则这两种只视为一种放法
输入
现给出N的值,请问有多少种不同的放法
输出
如题
样例输入
Sample input 1 2 Sample input 2 4
样例输出
Sample output 1 3 Sample output 2 8
提示
100%的数据,N<=10000
这道题目最大的难点在于,题目中说的:“如果一种方法是通过另一种方法翻转得到的则两种方法视为一种”,这也就是说咱们通过动规得到铺砖方法总数后还得排除掉通过翻转得到的那部分铺砖方法;
1.首先不考虑翻转我们知道dp[n]=dp[n-1]+2*dp[n-2], dp[n] 代表2行n列时的铺砖方法数,这部分就不细说了,关于动态归化的内容网上随便一搜就一堆的解释了,到这一步我们就已经算出不考虑翻转问题时的总铺砖数量为dp[n]了
伪代码:
int dp[1]=1; int dp[2]=3;
for(int i=3;i<=n;i++){
dp[i]=dp[i-1]+2*dp[i-2];
}
2.算出不考虑翻转问题的铺砖方法数之后,再来考虑翻转部分,先一张图解释下什么是翻转 如下图2行3列的两种铺砖方法就是其各自翻转后的样子:
这样一来你就应该想到任何一种铺法都能这样翻转一下对吧,那总铺砖方法数dp[n]/2就把重复的过滤掉了吗???
但是代码写出来后还是提交不过,为啥???仔细一想发现有种特殊情况被忽略了,就是沿中心轴对称的情况,如下2行3列的其中一种铺砖方法:
类似这种铺法不存在对应翻转之后的铺法的,因为它翻转之后还是它本身,那么我们假设沿中轴线对称的铺法数量为c[n],
所以最后实际铺砖方法数量为(dp[n]-c[n])/2+c[n]
3.那c[n]怎么得到?我们可以这样想,既然是对称的那中轴线左右两边的铺法肯定要是一样的,那c[n]=dp[n/2]吗???不完全对,
这里我们需要看n是奇数还是偶数,奇数时中轴线上必定是一个2X1的砖块c[n]=dp[n/2] (n/2取整)没问题,偶数时中轴线上可以是两个1X2或者1个2X2的砖块,或者中轴线上没有砖块.
如下图分别是中轴线上是两个1X2 1个2X2的砖块 无砖块
n=偶数时
可见中轴线上有砖块时,有两种情况2dp[n/2-1]+,中轴线上无砖块时dp[n/2]
所以**n为偶数时c[n]=2dp[n/2-1]+dp[n/2]*
所以最终结果:
if(n%2==0){
result = (dp[n]-2dp[n/2-1]+dp[n/2])/2+2*dp[n/2-1]+dp[n/2];
}else{
result =(dp[n]-dp[n/2])/2+dp[n/2];
}