hash表及带注释插头dp
struct hash_map
{
node s[SZ+10];int e,adj[SZ+10];
inline void init(){e=0;memset(adj,0,sizeof(adj));}
inline void update(LL state,int val,int cnt)
{
RG int i,pos=(state%SZ+(LL)val*SZ)%SZ;
for(i=adj[pos];i&&(s[i].state!=state||s[i].val!=val);i=s[i].next);
if(!i)s[++e].state=state,s[e].val=val,s[e].cnt=cnt,s[e].next=adj[pos],adj[pos]=e;
else s[i].cnt=(s[i].cnt+cnt)%mod;
} inline void find(LL state,int val)
{
RG int i,pos=(state%SZ+(LL)val*SZ)%SZ;
for(i=adj[pos];i&&(s[i].state!=state||s[i].val!=val);i=s[i].next);
if(!i)printf("no such val\n");
else printf("cnt=%d\n",s[i].cnt);
} }f[2];
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 1100000
#define mod 299989
#define P 8
#define N 100000000
ll n,m;
inline ll find(ll state,ll id){
return (state>>((id-1)<<1))&3;
}//看当前插头究竟是什么插头
//因为是四进制每两位代表一个状态
struct bignum
{
ll n[10],l;
bignum(){l=1,memset(n,0,sizeof(n));}
void clear(){while(l>1&&!n[l-1]) l--;}
void print(){
printf("%lld",n[l-1]);
for(ll i=l-2;i>=0;i--)
printf("%0*lld",P,n[i]);
printf("\n");
}
bignum operator +(bignum x)const{
bignum t=*this;
if(t.l<x.l) t.l=x.l;
t.l++;
for(ll i=0;i<t.l;i++){
t.n[i]+=x.n[i];
if(t.n[i]>=N){
t.n[i+1]+=t.n[i]/N;
t.n[i]%=N;
}
}
t.clear();
return t;
}
bignum operator =(ll x){
l=0;
while(x){
n[l++]=x%N;
x/=N;
}
return *this;
}
inline void operator +=(bignum b){*this=*this+b;}
}Ans;
struct hash_map
{
bignum val[mod];
ll key[A],hash[mod],size;
inline void init(){
memset(val,0,sizeof(val));
memset(key,-1,sizeof(key));size=0;
memset(hash,0,sizeof(hash));
}
inline void newhash(ll id,ll v){hash[id]=++size;key[size]=v;}
bignum &operator [] (const ll &state){
for(ll i=state%mod;;i=(i+1==mod)?0:i+1)
{
if(!hash[i]) newhash(i,state);
if(key[hash[i]]==state) return val[hash[i]];
}
}
}f[2];
inline void Set(ll &state,ll bit,ll val){
bit=(bit-1)<<1;
state|=3<<bit;
state^=3<<bit;
//把state高位先赋成0再把它赋成别的
state|=val<<bit;
//state表示状态
//因为插头的编号为0--m所以bit要-1
//因为是四进制,所以3<<
//全都是4进制
//2<<bit
//1<<bit
//貌似还能理解
//每两位代表一个具体状态
}
ll link(ll state,ll pos){
//找到对应的插头(用括号匹配的方式)然后
ll cnt=0,delta=(find(state,pos)==1)?1:-1;
//如果是左括号应该向右寻找右括号
//如果是右括号应该向左寻找左括号
for(ll i=pos;i&&i<=m+1;i+=delta)//一共m+1个插头
{
ll plug=find(state,i);
if(plug==1)
cnt++;//左括号数量++
else if(plug==2)
cnt--;//右括号数量++
if(cnt==0)//当左括号数量与右括号数量相等时找到匹配
return i;//找到了与当前插头对应的插头
}
return -1;
//当前状态是非法的找不到与之对应的插头
}
inline void education(ll x,ll y){
ll now=((x-1)*m+y)&1,last=now^1,tot=f[last].size;
f[now].init();
for(ll i=1;i<=tot;i++){
// printf("i=%lld\n",i);
ll state=f[last].key[i];//key状态
bignum Val=f[last].val[i];//取出上一次权值(方案数)
ll plug1=find(state,y),plug2=find(state,y+1);
//0--m编号,寻找轮廓线上编号y-1,y对应的插头
//至于为什么是y y+1,因为在上面函数里进行了减1
//编号为y-1是左右插头,y代表上下插头
if(link(state,y)==-1||link(state,y+1)==-1)
continue;
//当前括号无法找到匹配无解
if(!plug1&&!plug2){
if(x!=n&&y!=m){
//如果没有插头,直接拽过来两个插头相连(此题保证必须连通)
Set(state,y,1);
//在轮廓线上位置为y-1添加一个左括号
Set(state,y+1,2);
//y位置添加一个右括号
f[now][state]+=Val;
}
}
else if(plug1&&!plug2){
//拥有左右插头没有上下插头
//两种转移方式,转弯向下走
//这样插头状态不变
if(x!=n)
f[now][state]+=Val;
//向右连接一个插头
//向右推进要发生改变
if(y!=m){
Set(state,y,0);
Set(state,y+1,plug1);
f[now][state]+=Val;
}
}
else if(!plug1&&plug2){
//拥有上下插头而没有左右插头
//两种转移方式,向右转移
//这样插头状态不变
if(y!=m)
f[now][state]+=Val;
//向右连接一个插头
if(x!=n){
Set(state,y,plug2);
Set(state,y+1,0);
//plug2是左右插头让上下方向转弯
f[now][state]+=Val;
}
}
else if(plug1==1&&plug2==1){
//两个左括号插头相连接,然后让最靠左的右括号插头变成左括号插头
Set(state,link(state,y+1),1);
Set(state,y,0);
Set(state,y+1,0);
f[now][state]+=Val;
}
else if(plug1==1&&plug2==2){
//右插头是左括号插头,上插头是右括号插头,连在一起
//构成回路
if(x==n&&y==m)
Ans+=Val;
}
else if(plug1==2&&plug2==1){
//无脑合并
Set(state,y,0);
Set(state,y+1,0);
f[now][state]+=Val;
}
else if(plug1==2&&plug2==2){
//当你有左右插头右括号插头,上下插头为右插头
//合并为1,将最靠右左插头变为右插头
Set(state,link(state,y),2);
Set(state,y,0);
Set(state,y+1,0);
f[now][state]+=Val;
}
}
}
int main(){
scanf("%lld%lld",&n,&m);
if(n==1||m==1){printf("1\n");return 0;}
if(m>n) swap(n,m);
f[0].init();f[0][0]=1;
for(ll i=1;i<=n;i++)
{
for(ll j=1;j<=m;j++)
education(i,j);
if(i!=n){
ll now=(i*m)&1,tot=f[now].size;
for(ll j=1;j<=tot;j++)
f[now].key[j]<<=2;
}
}
Ans+=Ans;
Ans.print();
}
hash表及带注释插头dp的更多相关文章
- BZOJ.1210.[HNOI2004]邮递员(插头DP Hash 高精)
BZOJ 洛谷 http://www.cnblogs.com/LadyLex/p/7326874.html 插头DP.\(m+1\)个插头的状态需要用三进制表示:\(0\)表示无插头,\(1\)表示是 ...
- SQLServer之数据库表转化为实体类【带注释】
1.在开发过程中,有时候需要将数据库表转化为实体类.手敲除了不方便,还容易出错.本着DRY+懒人原则,参考了一位老司机的博客[见底部],并在其基础上进行了优化.[原先是不带注释的] DECLARE @ ...
- 四种方式带你层层递进解剖算法---hash表不一定适合寻找重复数据
一.题目描述 找出数组中重复的数字 > 在一个长度为 n 的数组 nums 里的所有数字都在 0-n-1 的范围内.数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次. ...
- 插头dp小结
插头dp: \(A:\)插头dp是什么? \(B:\)一种基于连通性状态压缩的动态规划问题 \(A:\)请问有什么应用呢? \(B:\)各种网格覆盖问题,范围允许状压解决,常用于计算方案数与联通块权值 ...
- 【Learning】插头DP
简介 插头DP(轮廓线DP)是用来解决网格图回路问题的一种算法. 插头DP解决的经典问题就是统计经过所有格子的哈密顿回路条数,某些格子有障碍. 如果问题稍微进阶一点的话,不一定要求路径是回路.路径 ...
- HDU 4113 Construct the Great Wall(插头dp)
好久没做插头dp的样子,一开始以为这题是插头,状压,插头,状压,插头,状压,插头,状压,无限对又错. 昨天看到的这题. 百度之后发现没有人发题解,hust也没,hdu也没discuss...在acm- ...
- HDU 4949 Light(插头dp、位运算)
比赛的时候没看题,赛后看题觉得比赛看到应该可以敲的,敲了之后发现还真就会卡题.. 因为写完之后,无限TLE... 直到后来用位运算代替了我插头dp常用的decode.encode.shift三个函数以 ...
- 插头DP专题
建议入门的人先看cd琦的<基于连通性状态压缩的动态规划问题>.事半功倍. 插头DP其实是比较久以前听说的一个东西,当初是水了几道水题,最近打算温习一下,顺便看下能否入门之类. 插头DP建议 ...
- HDU 1693 Eat the Trees(插头DP、棋盘哈密顿回路数)+ URAL 1519 Formula 1(插头DP、棋盘哈密顿单回路数)
插头DP基础题的样子...输入N,M<=11,以及N*M的01矩阵,0(1)表示有(无)障碍物.输出哈密顿回路(可以多回路)方案数... 看了个ppt,画了下图...感觉还是挺有效的... 参考 ...
随机推荐
- 去了字节跳动,才知道年薪40W的测试有这么多?
最近脉脉职言区有一条讨论火了: 哪家互联网公司薪资最'厉害'? 下面的评论多为字节跳动,还炸出了很多年薪40W的测试工程师 我只想问一句,现在的测试都这么有钱了吗? 前几天还有朋友说,从腾讯跳槽去 ...
- 引言:CTF新世界
1. CTF的昨天和今天 CTF(Capture The Flag)中文一般译作夺旗赛,在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式.CTF起源于1996年DEFCON全球黑客 ...
- useradd linux系统创建用户和设置密码简单脚本-1
useradd linux系统创建用户和设置密码简单脚本-1 linux_wangqiang 2019-12-04 20:51:18 65 收藏展开#!/bin/bash#快速创建用户 使用$1第一个 ...
- shell进阶之tree、pstree、lsof命令详解
一.tree命令详解: 主要功能是创建文件列表,将所有文件以树的形式列出来 -a 显示所有文件和目录. -A 使用ASNI绘图字符显示树状图而非以ASCII字符组合. -C 在文件和目录清单加上色彩, ...
- 2.2 CPU 上下文切换是什么意思?(下)
怎么查看系统的上下文切换情况 过多的上下文切换,会把 CPU 时间消耗在寄存器.内核栈以及虚拟内存等数据的保存和恢复上,缩短进程真正运行的时间,成了系统性能大幅下降的一个 元凶. 使用 vmstat ...
- java基础之8种基本数据类型
简单往往是最重要的,在刚刚学java的时候老师会给我们先讲这8种基本数据类型,今天再来做一个温习,[本文大部分参考了 https://zhuanlan.zhihu.com/p/25439066,在上面 ...
- flink的checkpoint页面监控
flink web页面中提供了针对Job Checkpoint相关的监控信息.Checkpoint监控页面共有overview.history.summary和configuration四个页签,分别 ...
- Linux C 文件IO
文件IO 2021-05-31 12:46:14 星期一 目录 文件IO 基础IO open 错误 creat read 一个例子 write close lseek 文件空洞 unlink删除 io ...
- Python小白的数学建模课-04.整数规划
整数规划与线性规划的差别只是变量的整数约束. 问题区别一点点,难度相差千万里. 选择简单通用的编程方案,让求解器去处理吧. 『Python小白的数学建模课 @ Youcans』带你从数模小白成为国赛达 ...
- 学习Git的一些总结
Git是以后公司工作必不可少的,所以早点了解使用它是很有必要的 一般国外的开源是GitHub 国内的是码云Gitee 至于git的安装教程,这里就不啰嗦啦,面向百度即可,安装完成鼠标右键会多几个选项: ...