zoukankan      html  css  js  c++  java
  • ZOJ 3256 Tour 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
    ");
        else printf("%d
    ",ans.a[1][0]);
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            init();
            solve();
        }
        return 0;
    }
    

      

  • 相关阅读:
    [原]OpenGL基础教程(四)VBO+纹理绘制四边形
    [原]OpenGL基础教程(二)多边形绘制
    [原]OpenGL基础教程(一)多边形绘制
    [原]VS2012编译GLEW 1.11
    [原]pomelo基础知识(一)
    数据挖掘算法之k-means算法
    送上今年微软的一道笔试题
    数据挖掘算法之决策树算法
    编程之美系列03
    编程之美系列02
  • 原文地址:https://www.cnblogs.com/bk-201/p/7493851.html
Copyright © 2011-2022 走看看