木块砌墙
题目详情:
用 1×1×1, 1× 2×1以及2×1×1的三种木块,
搭建K × 2^N × 1的墙,不能翻转、旋转(0<=N<=1024,1<=K<=5)
有多少种方案,输出结果对1000000007取模。
举例:
举个例子如给定N=1 K=2
答案是7,如下图所示
add 恶补了一下动态规划,矩阵快速幂,状态压缩,学习了http://www.matrix67.com/blog/archives/276,还有http://hi.baidu.com/scameeling/item/4527cdcd0bc4851fb67a2417
唉,终于凑出来了结果。。
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
#ifdef WIN32
#define LL __int64
#else
#define LL long long
#endif
#define SIZE (1<<k)
#define MAX_SIZE 32
using namespace std;
LL g_m;
class CMatrix
{
public:
LL element[MAX_SIZE][MAX_SIZE];
void setSize(int);
void setModulo(LL);
CMatrix operator* (CMatrix);
CMatrix power(int);
private:
int size;
LL modulo;
};
void CMatrix::setSize(int a)
{
for (int i=0; i<a; i++)
for (int j=0; j<a; j++)
element[i][j]=0;
size = a;
}
void CMatrix::setModulo(LL a)
{
modulo = a;
}
CMatrix CMatrix::operator* (CMatrix param)
{
CMatrix product;
product.setSize(size);
product.setModulo(modulo);
for (int i=0; i<size; i++)
for (int j=0; j<size; j++)
for (int k=0; k<size; k++)
{
product.element[i][j]+=element[i][k]*param.element[k][j];
product.element[i][j]%=modulo;
}
return product;
}
CMatrix CMatrix::power(int exp)
{
CMatrix tmp = (*this) * (*this);
if (exp==1) return *this;
else if (exp & 1) return tmp.power(exp/2) * (*this);
else return tmp.power(exp/2);
}
LL stat[MAX_SIZE][MAX_SIZE];
void dfs(LL t,LL curRowStk,LL preRowStk,LL b1,LL b2,LL p)
{
if (p>g_m)
{
if (b1==0 && b2==0)
{
stat[preRowStk][curRowStk]++;
}
return ;
}
if (b1==0 && b2==0)// 1
{
// 1
dfs(t,curRowStk<<1|1,preRowStk<<1 ,0,0,p+1);
dfs(t,curRowStk<<1|1,preRowStk<<1|1,1,0,p+1);
dfs(t,curRowStk<<1|1,preRowStk<<1|1 ,0,0,p+1);
dfs(t,curRowStk<<1 ,preRowStk<<1|1,0,0,p+1);
return ;
}
if (b1==1 && b2==0)
{
dfs(t,curRowStk<<1|1,preRowStk<<1|1,0,0,p+1);
return ;
}
dfs(t,curRowStk<<1|1,preRowStk<<1,0,0,p+1);
}
int calculate(int n,int k)
{
g_m = k;
memset(stat,0,sizeof(stat));
dfs(1,0,0,0,0,1);
CMatrix unit;
unit.setSize(SIZE);
for(int i=0; i<SIZE; i++)
{
for(int j=0; j<SIZE; j++)
{
unit.element[i][j]=stat[i][j];
}
}
LL p = 1000000007;
unit.setModulo(p);
CMatrix tmp;
if (n<1)
{
tmp = unit.power(1);
}
else
{
tmp = unit.power(2);
for (int i = 0; i < n-1; i++)
{
tmp = tmp.power(2);
}
}
return tmp.element[SIZE-1][SIZE-1];
}
int main()
{
for (int i = 0; i<10; i++)
{
for (int j = 1; j < 6; j++)
{
LL cc = calculate(i,j);
cout<<i<<" "<<j<<"=>"<<cc<<endl;
}
}
return 0;
}
这道题可能高三的时候也许能做出来。。。排列组合和数学归纳法都忘得差不多了。
因为题目厚度为1,所以这其实是个平面的题,跟俄罗斯方块一样。
只能尝试一下。
首先我们指定K=1,因为不涉及2*1*1的,能简单一点。假设n,k的结果为f(n,k)
用程序遍历的结果如下 f(6,1)的结果已经太大,无法遍历了。
f(0,1) = 1
f(1,1) = 2 = 1^2 + 1^2
f(2,1) = 5 = 1^2 + 2^2
f(3,1) = 34 = 3^2 + 5^2
f(4,1) = 1597 = 21^2 + 34^2
f(5,1) = 3524578 = 987^2 + 1597^2
很明显,f(n,1) 和f(n-1,1)是有很明显的关系的,那么这个987又是怎么来的呢
987 = 21*47 = 21*(34-21+34)
因此我们猜想
a = f(n,1)
b= f(n-1,1)
c = sqrt(a-b*b)
f(n+1,1) = a*a + [c*(b-c+b)]*[c*(b-c+b)]。
现在的脑子已经无力对此化简直接求f(n,1)了,应该是个复杂的指数函数吧。
明天有空在看一下k对f(n,k)的影响。
N:0 K:1-> 1
N:0 K:2-> 2
N:0 K:3-> 3
N:0 K:4-> 5
N:1 K:1-> 2
N:1 K:2-> 7
N:1 K:3-> 22
N:1 K:4-> 71
N:2 K:1-> 5
N:2 K:2-> 71
N:2 K:3-> 823
N:2 K:4-> 10012
N:3 K:1-> 34
N:3 K:2-> 7573
N:3 K:3-> 1222550
N:3 K:4-> 211351945
粗略的接近等比关系,但是不精确,很难猜了。
看了
http://www.matrix67.com/blog/archives/276
的问题9,感觉代码的方向不太对,但是感觉跟2*1还是有很大区别。
这原来是个动态规划,涉及矩阵,矩阵快速幂,状态转移等概念。
先看看书再说,
穷举的代码如下:
#include <iostream>
#include <math.h>
using namespace std;
long long total = 0;
int brick[1024*5];
void CountBrick(int deep,int n,int k)
{
if (deep >= k*n)
{
total++;
return;
}
if (brick[deep] == 0)
{
brick[deep] = 1;
CountBrick(deep+1,n,k);
brick[deep] = 0;
if ((deep+1)%k > 0 && (deep+1)<k*n)
{
if (brick[deep+1] == 0)
{
brick[deep] = 1;
brick[deep+1] = 1;
CountBrick(deep+2,n,k);
brick[deep] = 0;
brick[deep+1] = 0;
}
}
if (deep+k < k*n)
{
if (brick[deep+k] == 0)
{
brick[deep] = 1;
brick[deep+k] = 1;
CountBrick(deep+1,n,k);
brick[deep] = 0;
brick[deep+k] = 0;
}
}
}
else
{
CountBrick(deep+1,n,k);
}
}
int Answser(int n,int k)
{
total = 0;
CountBrick(0,pow((double)2,n),k);
return total;
}
int main()
{
for (int i = 0; i< 1024*5; i++)
{
brick[i] = 0;
}
for (int i = 0;i < 4;i++)
{
for (int j = 1; j < 5; j++)
{
cout<<"N:"<<i<<" K:"<<j<<"-> "<<Answser(i,j)<<endl;
}
cout<<endl;
}
}