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 ...
随机推荐
- Struts2拦截指定方法的拦截器
作者:禅楼望月 默认情况下,我们为一个Action配置一个拦截器,该拦截器会拦截该Action中的所有方法,但是有时候我们只想拦截指定的方法.为此,需要使用struts2拦截器的方法过滤特性. 要使用 ...
- java 自定义序列化
pom.xml 导包 创建自己的序列化类,继承 com.fasterxml.jackson.databind.JsonSerializer<T> 抽象类 重写 serialize() 方法 ...
- IE6,7,8支持css圆角
我们知道Webkit内核的浏览器支持-webkit-border-radius: 10px;属性(10px是圆角半径),可以直接解析出圆角;Firefox浏览器支持-moz-border-radius ...
- BZOJ3073 PA2011Journeys(线段树+bfs)
线段树优化建图裸题.建两棵线段树,一棵表示入一棵表示出.对题中所给的边新建一个虚拟点,将两段区间拆成线段树上对应区间,出线段树中对应区间所表示的点向虚拟点连边权0的边,虚拟点向入线段树中对应区间所表示 ...
- Codeforces Round #518 Div. 1没翻车记
A:设f[i][j][0/1]为前i个数第i位为j且第i位未满足/已满足限制的方案数.大力dp前缀和优化即可. #include<iostream> #include<cstdio& ...
- python监控服务器
import paramikoimport threadingimport reimport timeimport stringfrom sendmail import send_maildef ss ...
- Linux Uptime 命令,让你知道你的系统运行了多久
对于一些人来说系统运行了多久是无关紧要的,但是对于服务器管理员来说,这是相当重要的信息.服务器在运行重要应用的时候,必须尽量保证长时间的稳定运行,有时候甚至要求零宕机.那么我们怎么才能知道服务器运行了 ...
- PHP设计模式-工厂模式、单例模式、注册模式
本文参考慕课网<大话PHP设计模式>-第五章内容编写,视频路径为:http://www.imooc.com/video/4876 推荐阅读我之前的文章:php的设计模式 三种基本设计模式, ...
- 【BZOJ1146】【CTSC2008】网络管理 [整体二分]
网络管理 Time Limit: 50 Sec Memory Limit: 162 MB[Submit][Status][Discuss] Description M公司是一个非常庞大的跨国公司,在 ...
- [bzoj1015][JSOI2008]星球大战——并查集+离线处理
题解 给定一张图,支持删点和询问连通块个数 按操作顺序处理的话要在删除点的同时维护图的形态(即图具体的连边情况),这是几乎不可做的 我们发现,这道题可以先读入操作,把没删的点的边先连上,然后再倒序处理 ...