hdu 4332 Constructing Chimney

http://acm.hdu.edu.cn/showproblem.php?pid=4332

啊 又是一道伤不起的题呀   刚开始看了说是状态压缩 dp 然后自己就用滚动数组去写了 超时

n的大小是 10^9  当然超时 唉又仔细看了一下解题  用什么矩阵快速幂乘  好吧用了一个还是超时

看了标准代码没看懂呢 愁死了  最后把不同幂的矩阵打表  侥幸过了

........................................................ 废话分割线 ..........................................................

用0表示这个地方需要下面的一层来填充  1表示自己填充 。1的话有可能是平躺着 也有可能是竖着

上层用下层去更新时   必须满足 (i|j)==((1<<8)-1)和 i&j 不会有连续基数个1 

前者是因为 上层是0的地方下层必须是1 不能出现上下都是0的情况

后者是因为 连续基数个1 无法平躺着

由于后者原因最后取答案是也要有取舍

还有就是一层上全是1的情况 如果全是平躺着 会有两种方法 其余只有一种

把每个连乘幂 的矩阵打表记录 然后根据输入对相应的幂矩阵进行相乘

代码及其注释:

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<ctime>

#include<queue>

#include<cstring>

#include<set>

#include<cmath>

#include<algorithm>

#define LL long long

using namespace std;



const LL MOD=1000000007;

const int N=300;

LL ans[N];

LL matr[31][1<<8][1<<8];//2的几次幂 矩阵

bool can[N];//代表 是否有连续基数个1 有的话为false  否则为true

LL t[N];

int m=1<<8;

bool OK(int k)//判断是否有连续基数个1

{

    if(k==0)

    return true;

    int a[10];

    int i;

    for(i=0;i<8;++i)

    {

        a[i]=k%2;

        k=k/2;

    }

    i=0;

    while(a[i])

    ++i;

    for(int j=i+1;j<=i+8;++j)

    {

        if(a[j%8]==1)

        {

            if(a[(j+1)%8]==1)

            {

                ++j;

            }else

            {

                return false;

            }

        }

    }

    return true;



}

void add(int I)//把2的I次幂的矩阵乘到答案数组中

{

    for(int j=0;j<m;++j)

    {

        t[j]=0;

        for(int i=0;i<m;++i)

        {

            t[j]+=(ans[i]*matr[I][i][j])%MOD;

        }

    }

    for(int i=0;i<m;++i)

    {

        ans[i]=t[i]%MOD;

    }

}

void begin()//初始化

{

    memset(matr,0,sizeof(matr));

    for(int i=0;i<m;++i)

    for(int j=0;j<m;++j)

    if((i|j)==m-1&&can[i&j])

    matr[0][i][j]=1;

    matr[0][m-1][m-1]=2;//初始化 0 次幂矩阵 最后等于2的地方是因为 全是1 有两种摆法

    for(int w=0;w<30;++w)//对不同幂的矩阵 进行打表

    for(int l=0;l<m;++l)

    {

        for(int j=0;j<m;++j)

        {

            matr[w+1][l][j]=0;

            for(int i=0;i<m;++i)

            {

                matr[w+1][l][j]=(matr[w+1][l][j]+matr[w][l][i]*matr[w][i][j])%MOD;

            }

        }

    }



}

int main()

{

   //freopen("data.txt","r",stdin);

   memset(can,false,sizeof(can));

   for(int i=0;i<m;++i)

   if(OK(i))

   can[i]=true;

   else

   can[i]=false;

   begin();

   int T;

   scanf("%d",&T);

   for(int Case=1;Case<=T;++Case)

   {

       int n;

       scanf("%d",&n);

       memset(ans,0,sizeof(ans));

       ans[m-1]=1;//初始化答案数组为n等于1的情况

       --n;//所以连乘时 n减少1

       for(int i=0;n&&i<31;++i)

       {

           if(n%2==1)

           {

               add(i);

           }

           n=n>>1;

       }

       LL sum=0;

       for(int i=0;i<m;++i)

       if(can[i])

       {

           sum=(sum+ans[i])%MOD;

           if(i==m-1)//由于全是1 会有两种摆法的影响

           sum=(sum+ans[i])%MOD;

       }

       printf("Case %d: ",Case);

       cout<<sum<<endl;

   }

   return 0;

}

 

你可能感兴趣的:(struct)