题解  

  这题是一道非常好的插头题,与一般的按格转移的题目不同,由于m很大,要矩阵乘法,这题需要你做一个按列转移的插头DP。

  按列转移多少与按格转移不同,但大体上还是基于连通性进行转移。每一列只有右插头是对下一列的转移有影响的,那么我们只需要记录每一列的右插头的连通情况,用最小表示法表示为当前列的状态。在转移的时候,我们只知道上一列的右插头,即本列的左插头的情况,而上插头还需要自己记一个标记。

  那么我们具体分析:

  1、不存在上插头

    1、同时存在左插头和右插头,不需要修改当前插头,直接把上一列的右插头当做当前列的右插头

    2、只在左插头,即从上一列的某一个连通块转移过来,记录连通块。(左下插头)

    3、只在右插头,即此为一个新的连通块,打上标记,表明这是一个新的连通块。(右下插头)

  2、存在上插头

    1、同时存在左插头和右插头,一个格子里有三个插头,非法状态

    2、都不存在左插头和右插头,不需要修改当前插头,即从上往下。

    3、存在左插头

      1、上插头和左插头同属一个连通块,但不在最终状态(没有右插头)的右下角的格子里出现,非法状态

      2、上插头是左下插头,合并连通块,并删除这两个插头(这个合并比较特殊,因为两个都是已知的连通块,具体画图比较清晰)

      3、上插头是右下插头,合并连通块,删掉当前插头

    4、不存在左插头

      1、上插头是左下插头,合并连通块,删除左下插头

      2、上插头是右下插头,合并为新的连通块

  具体情况还是自己动手画图比较清晰。

  然后就到了矩乘的部分。首先考虑构造矩阵,g[i][j] = 1表示i状态能推到j状态,因此我们只需要枚举这些状态,一个一个判转移就可以了。

  初始的情况下,只存在全空的状态和0和N-1有插头的情况,因此答案就是矩阵快速幂后的ans[1][0],即从初始状态推向终止状态。

程序

 #include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm> using namespace std; #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define DWN(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define mset(a, b) memset(a, b, sizeof(a))
typedef long long LL;
const int MAXD = , HASH = , STATE = , MOD = ;
int n, m, code[MAXD], ch[MAXD];
struct HASHMAP
{
int head[HASH], nxt[STATE], state[STATE], siz;
void clear() { siz = , mset(head, -); }
int push(int x)
{
int pos = x%HASH, i = head[pos];
for (; i != -; i = nxt[i])
if (state[i] == x) return i;
state[siz] = x;
nxt[siz] = head[pos], head[pos] = siz++;
return siz-;
}
}hm;
struct Matrix
{
int mat[][], D;
Matrix operator * (const Matrix &AI) const
{
Matrix ret; ret.D = D;
REP(i, , D)
REP(j, , D)
{
LL sum = ;
REP(k, , D) sum += (LL)mat[i][k]*AI.mat[k][j];
ret.mat[i][j] = sum%MOD;
}
return ret;
}
}rc[], A, B; void decode(int x)
{
DWN(i, n, ) code[i] = x&, x >>= ;
} int encode()
{
int cnt = , ret = ;
mset(ch, -), ch[] = ;
REP(i, , n)
{
if (ch[code[i]] == -) ch[code[i]] = ++cnt;
ret <<= , ret |= ch[code[i]];
}
return ret;
} bool check(int st, int nxt)
{
decode(st);
int up = , k, cnt = ;
REP(i, , n)
{
if (up == )
{
if (!code[i] && !(nxt&(<<(i-)))) return false;
if (code[i] && (nxt&(<<(i-)))) continue ;
if (code[i]) up = code[i];
else up = -;
k = i;
}
else
{
if (code[i] && (nxt&(<<(i-)))) return false;
if (!code[i] && !(nxt&(<<(i-)))) continue ;
if (code[i])
{
if (up == code[i] && !(nxt&(<<(i-))) && (nxt || i != n)) return false;
if (up != -)
{
REP(j, , n) if (code[j] == code[i] && j != i) code[j] = code[k];
code[i] = code[k] = ;
}
else code[k] = code[i], code[i] = ;
}
else
{
if (up != -) code[i] = code[k], code[k] = ;
else code[i] = code[k] = n+(++cnt);
}
up = ;
}
}
if (up) return false;
return true;
} void init()
{
if (rc[n].D != )
{ B = rc[n]; return ; }
mset(rc[n].mat, );
hm.clear(), hm.push();
mset(code, ), code[] = code[n] = , hm.push(encode());
decode(hm.state[]);
for (int i = ; i < hm.siz; ++i)
REP(nxt, , ((<<n)-))
if (check(hm.state[i], nxt))
{
int j = hm.push(encode());
rc[n].mat[i][j] ++;
}
rc[n].D = hm.siz-;
B = rc[n];
} void work()
{
mset(A.mat, ); A.D = B.D;
REP(i, , A.D) A.mat[i][i] = ;
while (m > )
{
if (m&) A = A*B;
B = B*B, m >>= ;
}
if (!A.mat[][]) puts("Impossible");
else printf("%d\n", A.mat[][]);
} int main()
{
REP(i, , ) rc[i].D = ;
while (~scanf("%d %d", &n, &m))
init(), work();
return ;
}

ZOJ 3256 Tour in the Castle 插头DP 矩阵乘法的更多相关文章

  1. 【bzoj2004】[Hnoi2010]Bus 公交线路 状压dp+矩阵乘法

    题目描述 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计 ...

  2. 【bzoj3329】Xorequ 数位dp+矩阵乘法

    题目描述 输入 第一行一个正整数,表示数据组数据 ,接下来T行每行一个正整数N 输出 2*T行第2*i-1行表示第i个数据中问题一的解, 第2*i行表示第i个数据中问题二的解, 样例输入 1 1 样例 ...

  3. ZOJ - 3216:Compositions (DP&矩阵乘法&快速幂)

    We consider problems concerning the number of ways in which a number can be written as a sum. If the ...

  4. 【BZOJ-4386】Wycieczki DP + 矩阵乘法

    4386: [POI2015]Wycieczki Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 197  Solved: 49[Submit][Sta ...

  5. Luogu P4643 【模板】动态dp(矩阵乘法,线段树,树链剖分)

    题面 给定一棵 \(n\) 个点的树,点带点权. 有 \(m\) 次操作,每次操作给定 \(x,y\) ,表示修改点 \(x\) 的权值为 \(y\) . 你需要在每次操作之后求出这棵树的最大权独立集 ...

  6. LOJ.6074.[2017山东一轮集训Day6]子序列(DP 矩阵乘法)

    题目链接 参考yww的题解.本来不想写来但是他有一些笔误...而且有些地方不太一样就写篇好了. 不知不觉怎么写了这么多... 另外还是有莫队做法的...(虽然可能卡不过) \(60\)分的\(O(n^ ...

  7. 【BZOJ 3326】[Scoi2013]数数 数位dp+矩阵乘法优化

    挺好的数位dp……先说一下我个人的做法:经过观察,发现这题按照以往的思路从后往前递增,不怎么好推,然后我就大胆猜想,从前往后推,发现很好推啊,维护四个变量,从开始位置到现在有了i个数 f[i]:所有数 ...

  8. bzoj 3329: Xorequ【数位dp+矩阵乘法】

    注意第一问不取模!!! 因为a+b=a|b+a&b,a^b=a|b-a&b,所以a+b=a^b+2(a&b) x^3x==2x可根据异或的性质以转成x^2x==3x,根据上面的 ...

  9. luogu P4719 【模板】动态 DP 矩阵乘法 + LCT

    方法二:LCT+矩阵乘法 上文中,我们用线段树来维护重链上的各种矩阵转移. 第二种方法是将树链剖分替换为动态树. 我们知道,矩阵乘法 $\begin{bmatrix} F_{u,0} & F_ ...

随机推荐

  1. python作业Select版本FTP(第十周)

    SELECT版FTP: 使用SELECT或SELECTORS模块实现并发简单版FTP 允许多用户并发上传下载文件 思路解析: 1. 使用IO多路复用的知识使用SELECTORS封装好的SELECTOR ...

  2. E - Is It A Tree? 并查集判断是否为树

    题目链接:https://vjudge.net/contest/271361#problem/E 具体思路:运用并查集,每一次连接上一个点,更新他的父亲节点,如果父亲节点相同,则构不成树,因为入读是2 ...

  3. malloc原理和内存碎片【转】

    转自:http://www.cnblogs.com/zhaoyl/p/3820852.html 当一个进程发生缺页中断的时候,进程会陷入内核态,执行以下操作: 1.检查要访问的虚拟地址是否合法 2.查 ...

  4. python基础===map, reduce, filter的用法

    filter的用法: 这还是一个操作表list的内嵌函数'filter' 需要一个函数与一个list它用这个函数来决定哪个项应该被放入过滤结果队列中遍历list中的每一个值,输入到这个函数中如果这个函 ...

  5. Linux CGI编程基础【整理】

    Linux CGI编程基础 1.为什么使用CGI? 如前面所见,任何的HTML均是静态网页,它无法实现一些复杂的功能,而CGI可以为我们实现.如:a.列出服务器上某个目录中的文件,对目录中的文件进行操 ...

  6. rabbitmq集群搭建方法简介(测试机linux centos)【转】

    本文将介绍四台机器搭建rabbitmq集群: rabbitmq IP和主机名(每台机器已安装RabbitMQ 3.5.6, Erlang 18.1) 192.168.87.73 localhost73 ...

  7. Linux是对用户的密码的复杂度要求设置【转】

    那么Linux是如何实现对用户的密码的复杂度的检查的呢?其实系统对密码的控制是有两部分组成: 1 cracklib 2 /etc/login.defs pam_cracklib.so 才是控制密码复杂 ...

  8. 微信access_token和refresh_token保存于redis

    简介 通常理解的access_token和refresh_token access_token是用来对客户端进行认证的,类似与密码,有一定的有效期.当过期后可使用refresh_token重新获取一个 ...

  9. PyQt:eg4

    import sys from PyQt4 import QtCore from PyQt4 import QtGui class Form(QtGui.QDialog): def __init__( ...

  10. Educational Codeforces Round 25 D - Suitable Replacement(贪心)

    题目大意:给你字符串s,和t,字符串s中的'?'可以用字符串t中的字符代替,要求使得最后得到的字符串s(可以将s中的字符位置两两交换,任意位置任意次数)中含有的子串t最多. 解题思路: 因为知道s中的 ...