zoj 3256 Tour in the Castle(插头DP一条回路+矩阵连乘)

Tour in the Castle

Time Limit: 5 Seconds       Memory Limit: 32768 KB

After the final BOSS is defeated, the hero found that the whole castle is collapsing (very familiar scene, isn't it). Escape from the castle is easy, just need to cross a few rooms. But as the Hero is full of adventurous spirit, he decides to visit every room before he escape the castle.

The castle is a rectangle with N * M rooms in it. Two rooms are connected if they share a common edge. The hero starts in the top left room. And the bottom left room is the only way out. After the hero visits a room and leaves it, it will collapse immediately(Another familiar scene). So he can visit each room only once.

The diagram shows one tour over a castle with 4 * 10 rooms:

Input

There are multiply cases (<20), process to the end of file.

Each case contains a line with two Integer N and M (2 <= N <= 7, 1 <= M <=10^9).

Ouput

For each case, if it's impossible to visit every room exactly once and get to the bottom left room, output "Impossible". Otherwise, output the number of tours as it describe above. Beacause the answer can be huge, you just need to output the answer MOD 7777777.

Sample Input

3 2
3 3
4 10

Sample Output

Impossible
2
2329

Author:  WANG, Yelei
Source:  ZOJ Monthly, September 2009
题目: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3256
题意:给你一个n*m的方格,求一条路径通过所有格子,并且从左上角到达左下角,求总方案数,如果不存在方案输出impossble
分析:一眼看出是个插头DP一条回路问题,不过这题的M太大了,只能用上矩阵连乘优化,关键在于如何与矩阵连乘配合,一直以为是格子间的关系,所以想到死都想不明白,后来想起是列于列之间的关系= =
首先只有一个状态,也就是第0列固定的两个插头,然后用这个状态去拓展其他状态,拓展部分我是用插头DP的转移来做的,不是暴力枚举。。。
PS:本来应该1Y的不过我以为m+n是奇数就无解,貌似不是这样的= =
还有这回速度好慢啊,估计是矩阵连乘写挫了T_T
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int mm=66666;
const int mod=7777777;
typedef long long LL;
struct hashMap
{
    int h[mm],s[mm],p[mm],t;
    int push(int w)
    {
        for(int i=h[w];i>=0;i=p[i])
            if(s[i]==w)return i;
        s[t]=w,p[t]=h[w],h[w]=t;
        return t++;
    }
    void clear()
    {
        t=0,memset(h,-1,sizeof(h));
    }
}g,f[2];
LL a[222][222],b[222][222],c[222][222];
int i,j,k,n,m,g1,g2;
void Multi(LL a[222][222],LL b[222][222])
{
    for(i=0;i<g.t;++i)
        for(j=0;j<g.t;++j)
            for(c[i][j]=k=0;k<g.t;++k)
            {
                c[i][j]+=a[i][k]*b[k][j];
                if(c[i][j]>=mod)c[i][j]%=mod;
            }
    for(i=0;i<g.t;++i)
        for(j=0;j<g.t;++j)
            a[i][j]=c[i][j];
}
int Link(int s,int flag)
{
    int w,n=1,x=3<<(j<<1),a=(2-flag)<<(j<<1);
    while(n)
    {
        if(flag)a<<=2,x<<=2;
        else a>>=2,x>>=2;
        w=x&s;
        if(w)n+=(w==a)?1:-1;
    }
    return s^x;
}
void Work(int s)
{
    int e,w=j<<1,x=(s>>w)&15;
    if(x==9)return;
    if(!x)
    {
        if(j+1<n)f[g2].push(s^(9<<w));
    }
    else if(!(x&3)||!(x&12))
    {
        if(x&3)e=0,x|=x<<2;
        else e=1,x|=x>>2;
        if(!e||j+1<n)f[g2].push(s);
        if(e||j+1<n)f[g2].push(s^(x<<w));
    }
    else if(x==6)f[g2].push(s^(x<<w));
    else f[g2].push(Link(s^(x<<w),x==5));
}
void InitMatrix()
{
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    g.clear();
    g.push(1|(2<<((n-1)<<1)));
    for(i=0;i<g.t;++i)
    {
        f[0].clear();
        f[0].push(g.s[i]<<2);
        for(g2=j=0;j<n;++j)
            for(g1=g2,g2=!g2,f[g2].clear(),k=0;k<f[g1].t;++k)
                Work(f[g1].s[k]);
        for(k=0;k<f[g2].t;++k)
            a[g.push(f[g2].s[k])][i]=1;
        b[i][i]=1;
    }
}
void Solve()
{
    InitMatrix();
    while(m)
    {
        if(m&1)Multi(b,a);
        Multi(a,a);
        m>>=1;
    }
    LL ans;
    for(i=0;i<g.t;++i)
        if(g.s[i]==(9<<((n-2)<<1)))ans=b[i][0];
    if(ans)printf("%lld\n",ans);
    else puts("Impossible");
}
int main()
{
    while(~scanf("%d%d",&n,&m))Solve();
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值