hihocoder #1162 矩阵加速dp

#1162 : 骨牌覆盖问题·三

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

前两周里,我们讲解了2xN,3xN骨牌覆盖的问题,并且引入了两种不同的递推方法。
这一次我们再加强一次题目,对于给定的K和N,我们需要去求KxN棋盘的覆盖方案数。

提示:KxN骨牌覆盖

输入

第1行:2个整数N。表示棋盘宽度为k,长度为N。2≤K≤7,1≤N≤100,000,000

输出

第1行:1个整数,表示覆盖方案数 MOD 12357

样例输入
2 62247088
样例输出
1399
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MOD=12357;
int m,n;
struct Lu { int mx[140][140]; }L1,L2;
void dfs(int now,int next,int col)
{
    if(col==m){
        L1.mx[now][next]=1;//表示now状态能够转移到next状态
        return;
    }
    dfs((now<<1)+1,next<<1,col+1);//不放
    dfs(now<<1,(next<<1)+1,col+1);//竖放
    if(col+2<=m) dfs((now<<2)+3,(next<<2)+3,col+2);//横放
}
Lu multi(Lu a,Lu b)
{
    Lu c;
    for(int i=0;i<(1<<m);i++){
        for(int j=0;j<(1<<m);j++){
            c.mx[i][j]=0;
            for(int k=0;k<(1<<m);k++)
                c.mx[i][j]=(c.mx[i][j]+a.mx[i][k]*b.mx[k][j])%MOD;
        }
    }
    return c;
}
int solve(int x)
{
    memcpy(L2.mx,L1.mx,sizeof(L1.mx));
    while(x){
        if(x&1) L1=multi(L1,L2);
        L2=multi(L2,L2);
        x>>=1;
    }
    return L1.mx[(1<<m)-1][(1<<m)-1];//最后放满,转移到末状态
}
int main()
{
    while(scanf("%d%d",&m,&n)==2){
        memset(L1.mx,0,sizeof(L1.mx));
        dfs(0,0,0);
        int ans=solve(n-1);
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2017-10-26 19:53  luckilzy  阅读(457)  评论(0编辑  收藏  举报