hdu 4332 状态压缩的矩阵加速DP 谢sue神

来源:互联网 发布:软件测试因果图 编辑:程序博客网 时间:2024/06/05 01:56

题意:现在有无数的1*1*2的砖头,要垒成一个长度为N的烟囱。砖头可以竖起来,可以平着放,问题是当四块砖都平f放时,题目认为可以有两种情况。

做法:用0代表空,1代表覆盖。模拟每个截面放置砖头的情况后,可以发现不管怎么放,1的个数总是偶数,这可以用来化简。由于放置的特殊性,其实截面可以抽象成一个首尾可以相互影响的8位二进制数。如此,考虑所有情况,进行判断。

#include <cstdio>#include<cstring>#define mod 1000000007#define LMT 130#define LL long long//~的优先级比位移低//定义在结构体内就爆内存了..//少在main中定义//(x>>i)&1,才是判断啊//给矩阵乘法跪了using namespace std;class matrix{    public:    LL mat[LMT][LMT];    int n,m;    void init(void)    {        memset(mat,0,sizeof mat);    }    friend matrix operator*(matrix &,matrix &);};matrix matt,trans;int state[260],lim=1<<8;matrix operator *(matrix &a,matrix &b){    matrix tem;    tem.n=a.n;tem.m=b.m;    tem.init();    for(int k=0;k<a.m;k++)      for(int i=0;i<a.n;i++)      if(a.mat[i][k])          for(int j=0;j<b.m;j++)          tem.mat[i][j]=(tem.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;      return tem;}bool yes(int  code){    int s=0;    while(code)    {        s+=code&1;        code>>=1;    }    return s%2==0;}LL can(int a,int b){    int st,i,j;    bool end=false;    if(a==0)return b==255? 1LL:0;    for(i=0;i<8;i++)    {        j=(i+7)%8;        if((a&(1<<i))&&(a&(1<<j))==0)        {            st=i;            break;        }    }    for(i=st;i!=st||end==false;i=(i+1)%8)    {        end=true;        j=(i+1)%8;        if(0==(a&(1<<i)))        {            if(0==(b&(1<<i)))return 0;        }        else        {            if((a&(1<<j))&&(b&(1<<i))&&(b&(1<<j)))i++;            else if((b&(1<<i))==0)continue;            else return 0;        }    }    return 1LL;}void init(void){    lim=0;    memset(state,-1,sizeof(state));    for(int i=0;i<1<<8;i++)    if(yes(i))state[i]=lim++;    trans.init();    trans.m=trans.n=lim;    for(int i=0;i<1<<8;i++)       for(int j=i+1;j<1<<8;j++)       if(state[i]!=-1&&state[j]!=-1)           trans.mat[state[j]][state[i]]=trans.mat[state[i]][state[j]]=can(i,j);       trans.mat[lim-1][lim-1]=2;}matrix pow(matrix t,int n){    matrix tem;    tem.m=tem.n=lim;    tem.init();    for(int i=0;i<lim;i++)    tem.mat[i][i]=1;    while(n)    {        if(n&1)tem=tem*t;        t=t*t;        n>>=1;    }    return tem;}int main(void){    int T,I,n;    init();   scanf("%d",&T);    for(I=1;I<=T;I++)    {        scanf("%d",&n);        matt=pow(trans,n);        printf("Case %d: %I64d\n",I,matt.mat[lim-1][lim-1]);    }    return 0;}


原创粉丝点击