BZOJ.1210.[HNOI2004]邮递员(插头DP Hash 高精)

时间:2022-07-14 09:52:30

BZOJ

洛谷

http://www.cnblogs.com/LadyLex/p/7326874.html

插头DP。\(m+1\)个插头的状态需要用三进制表示:\(0\)表示无插头,\(1\)表示是左括号插头,\(2\)表示是右括号插头。为了方便用两位的二进制写。所以还需要个哈希表存状态。

转移的时候,对于左边上边这两个插头,如果某个插头为\(0\),很好转移。否则就分\(4\)种情况讨论下。不写了。。见上面的链接。

还需要高精度。其它就是些细节了。

转移时特判下边界外有插头就不转移,会方便很多。

实际方案数还不是特别多,高精可以用两个long long 实现。

因为状态也不多,线性探测的效率比链式哈希高很多。。

还有别忘把答案\(*2\)(反向走)。。

优化后:

//944kb	116ms
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const LL Base=(LL)1e18; int n,m;
struct BigInt
{
LL a,b;
BigInt() {a=0, b=0;}
inline void Init() {a=0, b=0;}
inline void Set(int x) {a=x, b=0;}
inline void operator =(const int x) {Set(x);}
inline void operator +=(const BigInt &x)//不能写 ++b,b+=x.b 因为是&...
{
a+=x.a, a>=Base?(b+=x.b+1,a-=Base):b+=x.b;
}
inline void Print()
{
b ? printf("%lld%018lld",b,a) : printf("%lld\n",a);
putchar('\n');
}
}Ans;
struct Hash_Table
{
#define mod 2501//状态数最多大概2200?
int top,sk[mod],hash[mod];
BigInt val[mod];
Hash_Table() {top=0, memset(hash,0xff,sizeof hash);}
inline void Init() {while(top) hash[sk[top--]]=-1;}
inline BigInt& operator [](const int s)
{//s可能是0
for(int x=s%mod; ; x=x+1==mod?0:x+1)
{
if(!~hash[x]) hash[x]=s, sk[++top]=x, val[x].Init();
if(hash[x]==s) return val[x];
}
}
}f[2]; inline int Get(const int s,const int bit) {return s>>(bit<<1)&3;}//s在bit位置的插头
inline void Upd(int &s,int bit,int v) {bit<<=1, s|=3<<bit, s^=3<<bit, s|=v<<bit;}//将s在bit位置的插头改为v
inline int Find(const int s,const int y,const int p)//找到与y位置的插头p 所对应的插头
{
int delta=p==1?1:-1/*向左/向右找*/,sum=delta;//if(!p) return y;
for(int i=y+delta,v; ~i&&i<=m; i+=delta)//i=0~m-1!
if(v=Get(s,i),sum+=v==2?-1:v==1,!sum) return i;
return -1;
}
void Work(const int n,const int m,const int x,const int y,Hash_Table &f,Hash_Table &g)
{
f.Init();
for(int i=1,tot=g.top; i<=tot; ++i)
{
int id=g.sk[i],s=g.hash[id],p1=Get(s,y-1),p2=Get(s,y),t1=p1?Find(s,y-1,p1):0,t2=p2?Find(s,y,p2):0;
if(t1==-1||t2==-1) continue;//
BigInt v=g.val[id];
if(!v.a) continue;
if(!p1&&!p2) {if(x!=n&&y!=m) Upd(s,y-1,1), Upd(s,y,2), f[s]+=v;}
else if(!p1&&p2)
{
if(y!=m) f[s]+=v;
if(x!=n) Upd(s,y-1,p2), Upd(s,y,0), f[s]+=v;
}
else if(p1&&!p2)
{
if(x!=n) f[s]+=v;
if(y!=m) Upd(s,y-1,0), Upd(s,y,p1), f[s]+=v;
}
else if(p1==1&&p2==1) Upd(s,y-1,0), Upd(s,y,0), Upd(s,t2,1), f[s]+=v;
else if(p1==1&&p2==2) {if(x==n&&y==m) Ans+=v;}
else if(p2==1) Upd(s,y-1,0), Upd(s,y,0), f[s]+=v;
else if(p2==2) Upd(s,y-1,0), Upd(s,y,0), Upd(s,t1,2), f[s]+=v;
}
} int main()
{
int n,m; scanf("%d%d",&n,&m);
if(m>n) std::swap(n,m); ::n=n, ::m=m;
if(m==1) return puts("1"),0;//!
int p=0; f[p].Init(), f[p][0]=1;
for(int i=1; i<=n; ++i)
{
for(int j=1; j<=m; ++j) p^=1, Work(n,m,i,j,f[p],f[p^1]);
if(i!=n)
{
for(int i=1,tot=f[p].top; i<=tot; ++i)
f[p].hash[f[p].sk[i]]<<=2;//这样会多花额外时间找状态吧=-= 不管了反正是快
// f[p^1].Init();
// for(int i=1,tot=f[p].top,s; i<=tot; ++i)
// s=f[p].hash[f[p].sk[i]], f[p^1][s<<2]=f[p][s];
// p^=1;
}
}
Ans+=Ans, Ans.Print(); return 0;
}

优化前:

//154108kb	1396ms
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Base 1000000000
typedef long long LL; int n,m;
struct BigInt
{
int a[5];
BigInt() {memset(a,0,sizeof a);}
inline void Init() {memset(a,0,sizeof a);}
inline void Set(int x) {a[0]=0; while(x) a[++a[0]]=x%Base, x/=Base;}
inline int& operator [](int x) {return a[x];}
inline BigInt operator +(const BigInt &x)const
{
BigInt res;
int l=std::max(a[0],x.a[0]);
for(int i=1; i<=l; ++i) res.a[i]+=a[i]+x.a[i], res[i]>=Base&&(++res.a[i+1]/*+=res.a[i]/Base*/, res.a[i]-=Base);
++l;
while(!res.a[l]) --l;
res.a[0]=l;
return res;
}
inline void operator =(const int x) {Set(x);}
inline void operator +=(const BigInt &x) {*this=*this+x;}
inline void Print()
{
printf("%d",a[a[0]]);
for(int i=a[0]-1; i>0; --i) printf("%09d",a[i]);
putchar('\n');
}
}Ans;
struct Hash_Table
{
#define mod 10007
#define N 2800000//1010101010101010101010 //4^{11}=4194304 不是3^{11}。。
int tot,top,sk[mod],H[mod],nxt[N],sta[N];
BigInt val[N];
Hash_Table() {tot=top=0;}
inline void AE(int u,int v) {nxt[v]=H[u], H[u]=v;}
inline void Init() {tot=0; while(top) H[sk[top--]]=0;}
inline BigInt& operator [](const int s)
{
int x=s%mod;//s可能是0,边表里的需要是s+1。也可以初始化H[x]=-1。
for(int i=H[x]; i; i=nxt[i])
if(i==s+1) return val[s];
if(!H[x]) sk[++top]=x;
AE(x,s+1), sta[++tot]=s, val[s].Init();
return val[s];
}
}f[2]; inline int Get(const int s,const int bit) {return s>>(bit<<1)&3;}//s在bit位置的插头
inline void Upd(int &s,int bit,int v) {bit<<=1, s|=3<<bit, s^=3<<bit, s|=v<<bit;}//将s在bit位置的插头改为v
inline int Find(const int s,const int y,const int p)//找到与y位置的插头p 所对应的插头
{
int delta=p==1?1:-1/*向左/向右找*/,sum=delta;//if(!p) return y;
for(int i=y+delta,v; ~i&&i<=m; i+=delta)//i=0~m-1!
if(v=Get(s,i),sum+=v==1?1:(v==2?-1:0),!sum) return i;
return -1;
}
void Work(const int n,const int m,const int x,const int y,Hash_Table &f,Hash_Table &g)
{
f.Init();
for(int i=1,tot=g.tot; i<=tot; ++i)
{
int s=g.sta[i],p1=Get(s,y-1),p2=Get(s,y),t1=p1?Find(s,y-1,p1):0,t2=p2?Find(s,y,p2):0;
if(t1==-1||t2==-1) continue;//
BigInt v=g.val[s];
if(!v[0]) continue;
if(!p1&&!p2) {if(x!=n&&y!=m) Upd(s,y-1,1), Upd(s,y,2), f[s]+=v;}
else if(!p1&&p2)
{
if(y!=m) f[s]+=v;
if(x!=n) Upd(s,y-1,p2), Upd(s,y,0), f[s]+=v;
}
else if(p1&&!p2)
{
if(x!=n) f[s]+=v;
if(y!=m) Upd(s,y-1,0), Upd(s,y,p1), f[s]+=v;
}
else if(p1==1&&p2==1) Upd(s,y-1,0), Upd(s,y,0), Upd(s,t2,1), f[s]+=v;
else if(p1==1&&p2==2) {if(x==n&&y==m) Ans+=v;}
else if(p2==1) Upd(s,y-1,0), Upd(s,y,0), f[s]+=v;
else if(p2==2) Upd(s,y-1,0), Upd(s,y,0), Upd(s,t1,2), f[s]+=v;
}
} int main()
{
int n,m; scanf("%d%d",&n,&m);
if(m>n) std::swap(n,m); ::n=n, ::m=m;
if(m==1) return puts("1"),0;//!
int p=0; f[p].Init(), f[p][0]=1;
for(int i=1; i<=n; ++i)
{
for(int j=1; j<=m; ++j) p^=1, Work(n,m,i,j,f[p],f[p^1]);
if(i!=n)
{
p^=1, f[p].Init();
for(int i=1,tot=f[p^1].tot,s; i<=tot; ++i)
s=f[p^1].sta[i], f[p][s<<2]=f[p^1][s];
}
}
Ans+=Ans, Ans.Print(); return 0;
}

BZOJ.1210.[HNOI2004]邮递员(插头DP Hash 高精)的更多相关文章

  1. bzoj 1210 &lbrack;HNOI2004&rsqb; 邮递员 插头dp

    插头dp板子题?? 搞了我一晚上,还tm全是抄的标程.. 还有高精,哈希混入,还是我比较弱,orz各种dalao 有不明白的可以去看原论文.. #include<cstdio> #incl ...

  2. 【BZOJ1210】&lbrack;HNOI2004&rsqb;邮递员 插头DP&plus;高精度

    [BZOJ1210][HNOI2004]邮递员 Description Smith在P市的邮政局工作,他每天的工作是从邮局出发,到自己所管辖的所有邮筒取信件,然后带回邮局.他所管辖的邮筒非常巧地排成了 ...

  3. vijos 1110小胖邮递员;bzoj 1210&colon; &lbrack;HNOI2004&rsqb;邮递员

    Description Smith在P市的邮政局工作,他每天的工作是从邮局出发,到自己所管辖的所有邮筒取信件,然后带回邮局.他所管辖的邮筒非常巧地排成了一个m*n的点阵(点阵中的间距都是相等的).左上 ...

  4. 无聊的 邮递员 插头dp

    邮递员想知道,如果他每天都用不同路线走过10×20个点阵邮筒,他必须活过多少个世纪才能走遍所有方案? 7:00 改完T1,开始肝插头dp 7:10 放弃,颓博客 7:20 学习插头dp 7:21 放弃 ...

  5. bzoj 2331&colon; &lbrack;SCOI2011&rsqb;地板 插头DP

    2331: [SCOI2011]地板 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 541  Solved: 239[Submit][Status] D ...

  6. 【BZOJ】2310&colon; ParkII 插头DP

    [题意]给定m*n的整数矩阵,求经过所有点至多一次路径的最大数值和.n<=8,m<=100. [算法]插头DP [题解]最小表示法确实十分通用,处理简单路径问题只需要状态多加一位表示独立插 ...

  7. BZOJ 2331 &lbrack;SCOI2011&rsqb;地板 ——插头DP

    [题目分析] 经典题目,插头DP. switch 套 switch 代码瞬间清爽了. [代码] #include <cstdio> #include <cstring> #in ...

  8. 「NOIP模拟赛」数位和乘积(dp,高精)

    统计方案数,要么组合数,要么递推(dp)了. 这是有模拟赛历史以来爆炸最狠的一次 T1写了正解,也想到开long long,但是开错了地方然后数组开大了结果100->0 T3看错题本来简单模拟又 ...

  9. BZOJ&period;1005&period;&lbrack;HNOI2008&rsqb;明明的烦恼&lpar;Prufer 高精 排列组合&rpar;

    题目链接 若点数确定那么ans = (n-2)!/[(d1-1)!(d2-1)!...(dn-1)!] 现在把那些不确定的点一起考虑(假设有m个),它们在Prufer序列中总出现数就是left=n-2 ...

随机推荐

  1. &lbrack;LeetCode&rsqb; Delete Node in a BST 删除二叉搜索树中的节点

    Given a root node reference of a BST and a key, delete the node with the given key in the BST. Retur ...

  2. shell脚本每天自动备份mysql数据库

    一.mysql提供了一个mysqldump的工具可以方便的导出导入数据库信息: 二.使用命令行shell测试执行mysqldump,理解必备的参数,查看生成的sql备份文件是否符合需求: /usr/b ...

  3. Nginx实现简易泛域名CDN节点

    如何使用Nginx泛域名解析+反向代理+静态资源缓存呢? 安装nginx,安装过程不再赘述,记得带上pcre.gzip.sub.status这几个模块,另外如果想开通在线清理缓存功能,需要安装ngx_ ...

  4. 查看C语言的方法名

    1,打开 Visual Studio 2008 x64 Win64 命令提示 2,查看dumpbin  –exports  [C动态库的路径]

  5. PHP实现http与https转化

    http://zyan.cc/post/142/ 最近在写PHP程序时,需要使浏览器在https和http之间转化,上网搜索相关信息,无奈只有最近在写PHP程序时,需要使浏览器在https和http之 ...

  6. 布局动画 LayoutAnimation

    简介 http://blog.csdn.net/pipisky2006/article/details/8317091 补间动画只能对一个控件使用,如果要对某一组控件播放一样的动画的话,可以考虑lay ...

  7. C&num;中静态类、静态方法和静态变量的简单说明

    静态方法与静态变量一样,属于类本身,而不属于哪个类的一个对象.调用一个被定义为static的方法,只有通过在它前面加上这个类的名称.一般定义里说是可以通过实例调用的.其他语言我还没测试,但是在C#中是 ...

  8. javascript预加载和延迟加载

    延迟加载javascript,也就是页面加载完成之后再加载javascript,也叫on demand(按需)加载,一般有一下几个方法: What can your tired old page, o ...

  9. memcached 与 redis 的区别和具体应用场景

    1. Memcached简介 Memcached是以LiveJurnal旗下Danga Interactive公司的Bard Fitzpatric为首开发的高性能分布式内存缓存服务器.其本质上就是一个 ...

  10. 修改LINUX的时区。

    新装的机器(redhat7)有几台时区不对: 百度了之后找到了以下解决方法输入 tz    依次选择Asia China  east China  Yes 1  然后 export TZ 新开对话发现 ...