zoj3256
好题,由m的范围知道这肯定是矩阵乘法加速插头dp,关键是怎么写
以往插头dp常用逐格递推,而这道题要求整行逐列递推
这样我们才能构造转移矩阵。
我们可以通过假象一个第0列来将路径转化为回路问题
逐列递推依然使用最小表示法,维护这一列每个格子向右的插头的连通性(最小表示法)
我们可以通过已知状态不断扩展出新的状态(初始显然只有无右插头和顶部底部有右插头两种情况)
对于一个已知列插头状态,我们穷举下一列每一个格子是否有插头,就知道了下一列每个格子是否有左插头和右插头
由于一个格子有且仅有两个插头,因此我们就确定了这一列的情况从而可以不断的扩展出新的合法状态
而最终合法状态不会超过150,接下来矩阵快速幂即可
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm> using namespace std;
typedef long long ll;
const int mo=;
const int has=;
int b[],v[],n,m,t;
struct node
{
int len,st[],p[has],nex[];
void clr()
{
len=;
memset(p,,sizeof(p));
}
int push(int nw)
{
int x=nw%has;
for (int i=p[x]; i>-; i=nex[i])
if (st[i]==nw) return i;
st[++len]=nw;
nex[len]=p[x]; p[x]=len;
return len;
}
} f; struct mat{
int a[][];
friend mat operator *(mat a,mat b)
{
mat c;
for (int i=; i<=t; i++)
for (int j=; j<=t; j++)
{
ll s=;
for (int k=; k<=t; k++) s+=(ll)a.a[i][k]*b.a[k][j];
c.a[i][j]=s%mo;
}
return c;
}
} ans,c; void get(int st)
{
for (int i=n-; i>=; i--)
{
b[i]=st&;
st>>=;
}
} int put()
{
memset(v,,sizeof(v)); v[]=;
int t=,st=;
for (int i=; i<n; i++)
{
if (v[b[i]]==-) v[b[i]]=++t;
st<<=;
st|=v[b[i]];
}
return st;
} bool check(int cur,int nw)
{
get(cur);
int pre=,k=,t=n;
for (int i=; i<n; i++)
{
int x=(nw>>i)&;
if (pre==)
{
if (!b[i]&&!x) return ;
if (b[i]&&x) continue;
if (b[i]) {pre=b[i];b[i]=;}
else pre=-;
k=i;
}
else {
if (b[i]&&x) return ;
if (!b[i]&&!x) continue;
if (b[i])
{
if (b[i]==pre&&(nw!=||i!=n-)) return ;
if (pre>)
{
for (int r=; r<n; r++)
if (i!=r&&b[r]==b[i]) b[r]=pre;
b[i]=;
}
else {b[k]=b[i],b[i]=;}
}
else {
if (pre>) b[i]=pre;
else b[i]=b[k]=++t;
}
pre=;
}
}
return pre==;
} void quick(int n)
{
memset(ans.a,,sizeof(ans.a));
for (int i=; i<=t; i++) ans.a[i][i]=;
while (n)
{
if (n&) ans=ans*c;
c=c*c;
n>>=;
}
} int main()
{
while (scanf("%d%d",&n,&m)!=EOF)
{
memset(b,,sizeof(b));
memset(c.a,,sizeof(c.a));
f.clr();
f.push();
b[]=b[n-]=; f.push(put());
for (int i=; i<=f.len; i++)
for (int j=; j<(<<n); j++)
if (check(f.st[i],j))
{
int k=f.push(put());
c.a[i][k]=;
}
t=f.len;
quick(m);
if (ans.a[][]==) puts("Impossible");
else printf("%d\n",ans.a[][]);
}
}
zoj3256的更多相关文章
- [ZOJ3256] Tour in the Castle
插头DP+矩阵乘法 m喜闻乐见地达到了10^9级别..而n<=7,并且没有障碍..所以列与列之间的转移时一样的..就可以上矩乘了. 感觉自己快没救了..看半天题解还是不懂.. http://ww ...
随机推荐
- 201621044079 week05-继承、多态、抽象类与接口
作业05-继承.多态.抽象类与接口 1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 接口 interface关键字 implements has-a;comparable co ...
- C语言100例01 PHP版(练习)
题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 程序分析:可填在百位.十位.个位的数字都是1.2.3.4.组成所有的排列后再去 掉不满足条件的排列. 代码: for ...
- 纯Div+Css制作的漂亮点击按钮和关闭按钮
纯Div+Css制作的漂亮点击按钮和关闭按钮,单击点击按钮也有效果.这些都不是图片.
- react router路由传参
今天,我们要讨论的是react router中Link传值的三种表现形式.分别为通过通配符传参.query传参和state传参. ps:进入正题前,先说明一下,以下的所有内容都是在react-rout ...
- Hello to the cruel world
- 线程--promise furture 同步
http://www.cnblogs.com/haippy/p/3279565.html std::promise 类介绍 promise 对象可以保存某一类型 T 的值,该值可被 future 对象 ...
- git使用笔记(五)打标签
By francis_hao Nov 19,2016 当一个项目commit了若干次到了一个可以发布版本的时候一般会给当前的分支状态打一个标签,就像我们常常见到的V1.0之类的. Git 使用的 ...
- centos7上安装docker-ce社区版
报错:Error: docker-ce-selinux conflicts with 2:container-selinux-2.12-2.gite7096ce.el7.noarch 转载:http: ...
- linux下将jpg,jpeg格式转为PDF
1.安装imagemagick(用其中的convert)和gthumb sudo apt-get install imagemagick gthumb 2.将tiff图片转换为png或jpeg ...
- ICE学习笔记一----运行官方的java版demo程序
建议新手和我一样,从官网下载英文文档,开个有道词典,慢慢啃. 官方文档下载: http://download.csdn.net/detail/xiong_mao_1/6300631 程序代码就不说了, ...