ZOJ 3256 Tour in the Castle 插头DP 矩阵乘法
题解
这题是一道非常好的插头题,与一般的按格转移的题目不同,由于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 矩阵乘法的更多相关文章
- 【bzoj2004】[Hnoi2010]Bus 公交线路  状压dp+矩阵乘法
		
题目描述 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计 ...
 - 【bzoj3329】Xorequ  数位dp+矩阵乘法
		
题目描述 输入 第一行一个正整数,表示数据组数据 ,接下来T行每行一个正整数N 输出 2*T行第2*i-1行表示第i个数据中问题一的解, 第2*i行表示第i个数据中问题二的解, 样例输入 1 1 样例 ...
 - ZOJ - 3216:Compositions (DP&矩阵乘法&快速幂)
		
We consider problems concerning the number of ways in which a number can be written as a sum. If the ...
 - 【BZOJ-4386】Wycieczki       DP + 矩阵乘法
		
4386: [POI2015]Wycieczki Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 197 Solved: 49[Submit][Sta ...
 - Luogu P4643 【模板】动态dp(矩阵乘法,线段树,树链剖分)
		
题面 给定一棵 \(n\) 个点的树,点带点权. 有 \(m\) 次操作,每次操作给定 \(x,y\) ,表示修改点 \(x\) 的权值为 \(y\) . 你需要在每次操作之后求出这棵树的最大权独立集 ...
 - LOJ.6074.[2017山东一轮集训Day6]子序列(DP 矩阵乘法)
		
题目链接 参考yww的题解.本来不想写来但是他有一些笔误...而且有些地方不太一样就写篇好了. 不知不觉怎么写了这么多... 另外还是有莫队做法的...(虽然可能卡不过) \(60\)分的\(O(n^ ...
 - 【BZOJ 3326】[Scoi2013]数数 数位dp+矩阵乘法优化
		
挺好的数位dp……先说一下我个人的做法:经过观察,发现这题按照以往的思路从后往前递增,不怎么好推,然后我就大胆猜想,从前往后推,发现很好推啊,维护四个变量,从开始位置到现在有了i个数 f[i]:所有数 ...
 - 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,根据上面的 ...
 - luogu P4719 【模板】动态 DP 矩阵乘法 + LCT
		
方法二:LCT+矩阵乘法 上文中,我们用线段树来维护重链上的各种矩阵转移. 第二种方法是将树链剖分替换为动态树. 我们知道,矩阵乘法 $\begin{bmatrix} F_{u,0} & F_ ...
 
随机推荐
- python并发编程之multiprocessing进程(二)
			
python的multiprocessing模块是用来创建多进程的,下面对multiprocessing总结一下使用记录. 系列文章 python并发编程之threading线程(一) python并 ...
 - Windows 7 64 位操作系统安装 Ubuntu 17.10
			
一.准备工作 1. DiskGenius:分区工具,为 Linux 建立单独的分区.(Linux 公社下载源) 2. UUI:Universal USB Installer,通用 U 盘安装器,用来制 ...
 - ELK&ElasticSearch5.1基础概念及配置文件详解【转】
			
1. 配置文件 elasticsearch/elasticsearch.yml 主配置文件 elasticsearch/jvm.options jvm参数配置文件 elasticsearch/log4 ...
 - ERROR in vc 6.0 (LINK : fatal error LNK1561: entry point must be defined)
			
导致错误 LINK : fatal error LNK1561: entry point must be defined 的原因有很多种, 网上可以搜到很多, 一般是函数入口没定义, 或者修改为/su ...
 - 查找内容grep命令
			
标准unix/linux下的grep通过以下参数控制上下文 grep -C 5 foo file 显示file文件中匹配foo字串那行以及上下5行 grep -B 5 foo file 显示foo及前 ...
 - cocos2d-x v2.2 IOS工程支持64-bit 遇坑记录
			
修改缘由 由于 iPhone 5S的A7 CPU iPhone 6(A8 CPU)都已经支持64-bit ARM 架构,据说64位处理器跑64代码会提高处理能力?因此二月一新提交appstore应 ...
 - Cookie 与 网络通信
			
通信协议是什么?(ftp.http.https.file...) 交流的规则 举例: 汉语.英语.法语.德语 (百度百科:通信协议) 通信协议是指双方实体完成通信或服务所必须遵循的规则和约定.通过通信 ...
 - EF – 1.模式
			
3种数据库 code first model first database first 创建EF http://www.cnblogs.com/tangge/p/3834578.html DbSet ...
 - Web开发入门知识小总结
			
原来是写给 http://www.zhihu.com/question/22689579 的答案,也算是学了一学期web课程后的一点小总结,搬运到博客里存一下吧~ ================== ...
 - Validating a Model