好题,由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的更多相关文章

  1. [ZOJ3256] Tour in the Castle

    插头DP+矩阵乘法 m喜闻乐见地达到了10^9级别..而n<=7,并且没有障碍..所以列与列之间的转移时一样的..就可以上矩乘了. 感觉自己快没救了..看半天题解还是不懂.. http://ww ...

随机推荐

  1. 算法(13)Contiguous Array

    题目:找出数组的一个子数组,要求这个子数组中0和1的数量相等,找出最大长度的这样的数组! 思路:也是受网上算法的启发吧,用一个 语言:如何初始化一个unordered_map<int,int&g ...

  2. hw_breakpoint使用方法

    hw_breakpoint 使用方法 kprobe在 do_page_fault 函数中不能使用,那么如果真要在这里打点怎么办呢?看看hw_breakpoint是否可用: 事实证明,即便 hw_bre ...

  3. 通过数据库评估存储设备IO性能-Oracle11gIO校准功能介绍

    通过数据库评估存储设备IO性能 ---------Oracle11g IO校准功能介绍 前言 I/O子系统是ORACLE数据库的一个重要组成部分,因为I/O操作是贯穿数据库管理全过程,它操作的对象包括 ...

  4. Access-Control-Allow-Methods: OPTIONS & CORS

    Access-Control-Allow-Methods: OPTIONS CORS https://stackoverflow.com/questions/20478312/default-valu ...

  5. C&C++——C与C++知识点

    C++知识点系列之一(转+整理) 编程时类声明后面千万不要忘了加分号,不然会出现很多错误!! c系列之一一.#include “filename.h”和#include<filename.h&g ...

  6. JQuery用鼠标选文字来发新浪微博

    最近注意到新浪博客有个小功能,就是当鼠标选中一段文字时会浮现一个小图片,点击这个图片可以把选中内容发送到新浪微博,一时兴起昨晚就写了一个Demo玩了一下,代码超简单,没优化,有兴趣的朋友可以自己改进. ...

  7. 深入研究JavaScript的事件机制

    本篇开始将回顾下Javascript的事件机制.同时会从一个最小的函数开始写到最后一个具有完整功能的,强大的事件模块.为叙述方便将响应函数/回调函数/事件Listener/事件handler都称为事件 ...

  8. taotao用户登录springMVC拦截器的实现

    在springMVC中写拦截器,只需要两步: 一.写 java 拦截器类,实现 interceptor 拦截器接口. 二.在 springMVC 的xml配置文件中,配置我们创建的拦截器对象及其拦截目 ...

  9. HDU3338:Kakuro Extension(最大流)

    Kakuro Extension Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  10. mmall项目之问题一(mavenplugin问题)

    在进行mybatis逆向工程到时候,报错,提示maven plugin 错误,提示missing..... 解决办法: 因为之前到pom中忘记了加版本信息,添加后错误消失: