题目:http://acm.hdu.edu.cn/showproblem.php?pid=2606
题意:有四种砖规格分别是 1*1 2*2 3*3 4*4,现在已知一个4*n的矩形,问刚好铺满这个矩形有多少种方案?
解题:题目说的是4*n的矩形,我把矩形倒过来看,也就是一个n*4的矩形,也就是只有四列的矩形
dp[i] 表示铺满前i行的方案数,对于第i行的4个方块,它只可能这几种情况中一种:1111 2211 1122 1221 2222 3331 1333 4444
对于1111 的摆放,得到 dp[i] += dp[i-1]; 也就是最后一行我确定了,然后前面的i-1行随便你放,下面类似。
对于3331 1333的摆放,得到dp[i] += dp[i-3]*2;
对于4444的摆放,得到 dp[i] += dp[i-4];
然而 对于2211 1122 1221 2222 的摆放,这就有点麻烦了,你可能会问为什么不能直接 dp[i] += dp[i-2] * 4
如果单纯加上dp[i-2]*4 就会缺失了一些特殊情况,比如3*4的矩阵,dp[i-2]*4 代表的情况如下:
1111 1111 1111 1111
2211 1221 1122 2222
2211 1221 1122 2222
但缺少了这两种特殊情况
2211 1122
2222 2222
1122 2211
我们可以知道只有2*2这种砖块,才会存在这种问题。因为 22xx,剩下的两格xx可以是22 或者11,如果是333x,x就只能是1。
这部分特殊怎么推,语言很难描述,也怕讲错了,不过只需要画出4*4的情况,自己揣摩一下就可以了,这部分特殊情况的解是 top[i-3]*2 (top[n] = dp[0] + dp[1] + .. + dp[n])。
边界:dp[0]=dp[1] =1 dp[2] = 5
#include<stdio.h>
typedef long long ll;
ll dp[100+10]={1,1,5,13};// dp[i]表示铺满前 i 行的方案数
ll top[100+10]={1,2,7,20};// top[n] = dp[0] + dp[1] + dp[2] +...+dp[n]
const ll mod = 19890907;
void init()
{
for(int i=4;i<=100;i++)
{
dp[i] = dp[i-1]%mod;
dp[i] = (dp[i] + dp[i-2]*4%mod)%mod;
dp[i] = (dp[i] + top[i-3]*2%mod) %mod;
dp[i] = (dp[i] + dp[i-3]*2%mod)%mod;
dp[i] = (dp[i] + dp[i-4])%mod;
top[i] = (top[i-1] + dp[i]) %mod;
}
}
int main()
{
int t;
scanf("%d",&t);
init();
while(t--)
{
int n;
scanf("%d",&n);
printf("%lld\n",dp[n]%mod);
}
return 0;
}//15ms c++
加油吧,渣科