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\n");
    else printf("%d\n",ans.a[1][0]);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        solve();
    }
    return 0;
}

  

时间: 2024-11-18 06:00:54

ZOJ 3256 Tour in the Castle 矩阵快速幂加速的相关文章

zoj 2974 Just Pour the Water矩阵快速幂

Just Pour the Water Time Limit: 2 Seconds      Memory Limit: 65536 KB Shirly is a very clever girl. Now she has two containers (A and B), each with some water. Every minute, she pours half of the water in A into B, and simultaneous pours half of the

HDU 5950 - Recursive sequence - [矩阵快速幂加速递推][2016ACM/ICPC亚洲区沈阳站 Problem C]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5950 Farmer John likes to play mathematics games with his N cows. Recently, they are attracted by recursive sequences. In each turn, the cows would stand in a line, while John writes two positive numbers

zoj 3538 Arrange the Schedule(矩阵快速幂)

Arrange the Schedule Time Limit: 1 Second      Memory Limit: 65536 KB In Summer 2011, the ZJU-ICPC Team has a n-days training schedule. ZJU-ICPC Team has been divided into 4 Group: Akiba, BiliBili, CIA, Double(Group A, B, C, D). There is a group in c

【插头DP】 ZOJ 3256 Tour in the Castle

通道:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3256 题意:简单路径-左上角走到左下角的路径方案数. 思路:M太大,需快速幂,预处理所有状态即可. 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 5 using namespace std; 6 7 const int maxn = 10001; 8 const

POJ3070 Fibonacci(矩阵快速幂加速递推)【模板题】

题目链接:传送门 题目大意: 求斐波那契数列第n项F(n). (F(0) = 0, F(1) = 1, 0 ≤ n ≤ 109) 思路: 用矩阵乘法加速递推. 算法竞赛进阶指南的模板: #include <iostream> #include <cstring> using namespace std; const int MOD = 10000; void mul(int f[2], int base[2][2]) { int c[2]; memset(c, 0, sizeof

Bubble Cup X - Finals [Online Mirror] B. Neural Network country 矩阵快速幂加速转移

B. Neural Network country time limit per test 2 seconds memory limit per test 256 megabytes Due to the recent popularity of the Deep learning new countries are starting to look like Neural Networks. That is, the countries are being built deep with ma

POJ3420 递推+矩阵快速幂

POJ3420 很有趣的覆盖问题 递归推导如下: f[n] = f[n-1] + 4*f[n-2] + 2 * [ f[n-3] + f[n-5] + f[n-7] +.... ] + 3 *  [ f[n-4] + f[n-6] + f[n-8] +.... ] ; (1) f[n - 2] = f[n-3] + 4*f[n-4] + 2 * [ f[n-5] + f[n-7] + f[n-9] +.... ] + 3 *  [ f[n-6] + f[n-8] + f[n-10] +....

COJ 1208 矩阵快速幂DP

题目大意: f(i) 是一个斐波那契数列 , 求sum(f(i)^k)的总和 由于n极大,所以考虑矩阵快速幂加速 我们要求解最后的sum[n] 首先我们需要思考 sum[n] = sum[n-1] + f(i+1)^k 那么很显然sum[n-1]是矩阵中的一个元素块 那么f(i+1)^k怎么利用f(i) , f(i-1)来求 f(i+1)^k = (f(i) + f(i-1)) ^ k 假如k = 1 , 可以看出f(i+1) = f(i-1) + f(i) (1,1) k = 2 , 可以看出

UVA-11625-Nice Prefixes (DP+矩阵快速幂)

题目(vjudge) 题面 题意: 你有K个字母,你需要用K个字母组成L长度的字符串,定义对于该字符串的任意前缀P 必须满足    ,输出方案数%1000000007的值. 思路: 首先可以想到一种简单的dp方程  dp [ len ] [ a ]  [b ]  表示当前字符串长度为len  个数为最多的字母有 a个  个数次多的有b个  (那么个数最少的有k-a-b个)状态数有 100*100,没办法矩阵快速幂加速dp. 考虑对于某个固定长度 len  如果确定 a,容易发现 b = (len