码迷,mamicode.com
首页 > 其他好文 > 详细

ZOJ 3256 Tour in the Castle 矩阵快速幂加速

时间:2017-09-08 13:22:21      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:ret   stream   pos   long   return   连通块   加速   int   acm   

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3256

题意:给一个n*m的棋盘,求从左上到左下的经过所有格子的方案数

 

在左边加一列问题就变成了求回路

由于m很大,所以我们需要按列dp

构造出矩阵后,用矩阵快速幂加速

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int mod=7777777;
const int HASH=419;
const int STATE=1010;
int n,m,D;
int code[10],ch[10];
struct p
{
    int a[200][200];
    p(){memset(a,0,sizeof(a));}
    p operator *(const p&t)
    {
        p ans;
        for(int i=0;i<D;i++)
            for(int j=0;j<D;j++)
            {
                ll tem=0;
                for(int k=0;k<D;k++)
                    tem+=1LL*a[i][k]*t.a[k][j];
                ans.a[i][j]=tem%mod;
            }
        return ans;
    }
};
p g;
p qpow(p x,int m)
{
    p ans;
    for(int i=0;i<D;i++)
        ans.a[i][i]=1;
    while(m)
    {
        if (m&1) ans=ans*x;
        x=x*x;
        m>>=1;
    }
    return ans;
}
struct hashmap
{
    int head[HASH],nextt[STATE],sz;
    int state[STATE];
    void init()
    {
        sz=0;
        memset(head,-1,sizeof(head));
    }
    int push(int st)
    {
        int h=st%HASH;
        for(int i=head[h];i!=-1;i=nextt[i])
            if (state[i]==st)
                return i;
        state[sz]=st;
        nextt[sz]=head[h];
        head[h]=sz++;
        return sz-1;
    }
}hm;
void decode(int st)
{
    for(int i=n-1;i>=0;i--)
    {
        code[i]=st&3;
        st>>=2;
    }
}
int encode()
{
    int cnt=1,st=0;
    memset(ch,-1,sizeof(ch));
    ch[0]=0;
    for(int i=0;i<n;i++)
    {
        if (ch[code[i]]==-1) ch[code[i]]=cnt++;
        st<<=2;
        st|=ch[code[i]];
    }
    return st;
}
bool check(int st,int nst)
{
    decode(st);
    int flag=0;//当前格子是否有上插头
    int k,cnt=0;
    for(int i=0;i<n;i++)
    {
        if (flag==0)//没有
        {
            if (!code[i]&&!(nst>>i&1)) return false;//没有左右插头
            if (code[i]&&nst>>i&1) continue;//有左右插头
            if (code[i]) flag=code[i];//插头从左边来,向下延伸
            else flag=-1;//插头从下面来,向右延伸
            k=i;
        }
        else
        {
            if (code[i]&&nst>>i&1) return false;//有上左右插头
            if (!code[i]&&!(nst>>i&1)) continue;//没有左右插头,向下延伸
            if (code[i])//有左插头
            {
                if (code[i]==flag&&(i!=n-1||nst!=0)) return false;//如果不是最后一个格子,不能合并相同的插头
                if (flag>0)//合并插头
                {
                    for(int j=0;j<n;j++)
                        if (code[j]==code[i]&&j!=i)
                            code[j]=code[k];
                    code[i]=code[k]=0;
                }
                else//向右延伸
                {
                    code[k]=code[i];
                    code[i]=0;
                }
            }
            else
            {
                if (flag>0)//向右延伸
                {
                    code[i]=code[k];
                    code[k]=0;
                }
                else//建立新的连通块
                {
                    code[i]=code[k]=n+cnt;
                    cnt++;
                }
            }
            flag=0;
        }
    }
    if (flag!=0) return false;
    return true;
}
void init()//构造矩阵
{
    hm.init();
    memset(code,0,sizeof(code));
    code[0]=code[n-1]=1;
    hm.push(0);
    hm.push(encode());
    memset(g.a,0,sizeof(g.a));
    for(int i=1;i<hm.sz;i++)
    {
        int st=hm.state[i];
        for(int nst=0;nst<1<<n;nst++)
            if (check(st,nst))
            {
                int j=hm.push(encode());
                g.a[i][j]=1;
            }
    }
    D=hm.sz;
}
void solve()
{
    p ans=qpow(g,m);
    if (ans.a[1][0]==0) printf("Impossible\n");
    else printf("%d\n",ans.a[1][0]);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        solve();
    }
    return 0;
}

  

ZOJ 3256 Tour in the Castle 矩阵快速幂加速

标签:ret   stream   pos   long   return   连通块   加速   int   acm   

原文地址:http://www.cnblogs.com/bk-201/p/7493851.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!