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

Posted BK_201

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZOJ 3256Tour in the Castle 矩阵快速幂加速相关的知识,希望对你有一定的参考价值。

题目: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 3256Tour in the Castle 矩阵快速幂加速的主要内容,如果未能解决你的问题,请参考以下文章

zoj4110 Strings in the Pocket(manacher)

ZOJ4108 Fibonacci in the Pocket

ZOJ4110 Strings in the Pocket(2019浙江省赛)

2019浙江省赛K zoj4110 Strings in the Pocket(manachar)

Brief Tour of the Standard Library

如何正确的探索 Microsoft Ignite The Tour