BZOJ

洛谷

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

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

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

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

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

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

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

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

优化后:

  1. //944kb 116ms
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. typedef long long LL;
  6. const LL Base=(LL)1e18;
  7. int n,m;
  8. struct BigInt
  9. {
  10. LL a,b;
  11. BigInt() {a=0, b=0;}
  12. inline void Init() {a=0, b=0;}
  13. inline void Set(int x) {a=x, b=0;}
  14. inline void operator =(const int x) {Set(x);}
  15. inline void operator +=(const BigInt &x)//不能写 ++b,b+=x.b 因为是&...
  16. {
  17. a+=x.a, a>=Base?(b+=x.b+1,a-=Base):b+=x.b;
  18. }
  19. inline void Print()
  20. {
  21. b ? printf("%lld%018lld",b,a) : printf("%lld\n",a);
  22. putchar('\n');
  23. }
  24. }Ans;
  25. struct Hash_Table
  26. {
  27. #define mod 2501//状态数最多大概2200?
  28. int top,sk[mod],hash[mod];
  29. BigInt val[mod];
  30. Hash_Table() {top=0, memset(hash,0xff,sizeof hash);}
  31. inline void Init() {while(top) hash[sk[top--]]=-1;}
  32. inline BigInt& operator [](const int s)
  33. {//s可能是0
  34. for(int x=s%mod; ; x=x+1==mod?0:x+1)
  35. {
  36. if(!~hash[x]) hash[x]=s, sk[++top]=x, val[x].Init();
  37. if(hash[x]==s) return val[x];
  38. }
  39. }
  40. }f[2];
  41. inline int Get(const int s,const int bit) {return s>>(bit<<1)&3;}//s在bit位置的插头
  42. inline void Upd(int &s,int bit,int v) {bit<<=1, s|=3<<bit, s^=3<<bit, s|=v<<bit;}//将s在bit位置的插头改为v
  43. inline int Find(const int s,const int y,const int p)//找到与y位置的插头p 所对应的插头
  44. {
  45. int delta=p==1?1:-1/*向左/向右找*/,sum=delta;//if(!p) return y;
  46. for(int i=y+delta,v; ~i&&i<=m; i+=delta)//i=0~m-1!
  47. if(v=Get(s,i),sum+=v==2?-1:v==1,!sum) return i;
  48. return -1;
  49. }
  50. void Work(const int n,const int m,const int x,const int y,Hash_Table &f,Hash_Table &g)
  51. {
  52. f.Init();
  53. for(int i=1,tot=g.top; i<=tot; ++i)
  54. {
  55. 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;
  56. if(t1==-1||t2==-1) continue;//
  57. BigInt v=g.val[id];
  58. if(!v.a) continue;
  59. if(!p1&&!p2) {if(x!=n&&y!=m) Upd(s,y-1,1), Upd(s,y,2), f[s]+=v;}
  60. else if(!p1&&p2)
  61. {
  62. if(y!=m) f[s]+=v;
  63. if(x!=n) Upd(s,y-1,p2), Upd(s,y,0), f[s]+=v;
  64. }
  65. else if(p1&&!p2)
  66. {
  67. if(x!=n) f[s]+=v;
  68. if(y!=m) Upd(s,y-1,0), Upd(s,y,p1), f[s]+=v;
  69. }
  70. else if(p1==1&&p2==1) Upd(s,y-1,0), Upd(s,y,0), Upd(s,t2,1), f[s]+=v;
  71. else if(p1==1&&p2==2) {if(x==n&&y==m) Ans+=v;}
  72. else if(p2==1) Upd(s,y-1,0), Upd(s,y,0), f[s]+=v;
  73. else if(p2==2) Upd(s,y-1,0), Upd(s,y,0), Upd(s,t1,2), f[s]+=v;
  74. }
  75. }
  76. int main()
  77. {
  78. int n,m; scanf("%d%d",&n,&m);
  79. if(m>n) std::swap(n,m); ::n=n, ::m=m;
  80. if(m==1) return puts("1"),0;//!
  81. int p=0; f[p].Init(), f[p][0]=1;
  82. for(int i=1; i<=n; ++i)
  83. {
  84. for(int j=1; j<=m; ++j) p^=1, Work(n,m,i,j,f[p],f[p^1]);
  85. if(i!=n)
  86. {
  87. for(int i=1,tot=f[p].top; i<=tot; ++i)
  88. f[p].hash[f[p].sk[i]]<<=2;//这样会多花额外时间找状态吧=-= 不管了反正是快
  89. // f[p^1].Init();
  90. // for(int i=1,tot=f[p].top,s; i<=tot; ++i)
  91. // s=f[p].hash[f[p].sk[i]], f[p^1][s<<2]=f[p][s];
  92. // p^=1;
  93. }
  94. }
  95. Ans+=Ans, Ans.Print();
  96. return 0;
  97. }

优化前:

  1. //154108kb 1396ms
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define Base 1000000000
  6. typedef long long LL;
  7. int n,m;
  8. struct BigInt
  9. {
  10. int a[5];
  11. BigInt() {memset(a,0,sizeof a);}
  12. inline void Init() {memset(a,0,sizeof a);}
  13. inline void Set(int x) {a[0]=0; while(x) a[++a[0]]=x%Base, x/=Base;}
  14. inline int& operator [](int x) {return a[x];}
  15. inline BigInt operator +(const BigInt &x)const
  16. {
  17. BigInt res;
  18. int l=std::max(a[0],x.a[0]);
  19. 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);
  20. ++l;
  21. while(!res.a[l]) --l;
  22. res.a[0]=l;
  23. return res;
  24. }
  25. inline void operator =(const int x) {Set(x);}
  26. inline void operator +=(const BigInt &x) {*this=*this+x;}
  27. inline void Print()
  28. {
  29. printf("%d",a[a[0]]);
  30. for(int i=a[0]-1; i>0; --i) printf("%09d",a[i]);
  31. putchar('\n');
  32. }
  33. }Ans;
  34. struct Hash_Table
  35. {
  36. #define mod 10007
  37. #define N 2800000//1010101010101010101010 //4^{11}=4194304 不是3^{11}。。
  38. int tot,top,sk[mod],H[mod],nxt[N],sta[N];
  39. BigInt val[N];
  40. Hash_Table() {tot=top=0;}
  41. inline void AE(int u,int v) {nxt[v]=H[u], H[u]=v;}
  42. inline void Init() {tot=0; while(top) H[sk[top--]]=0;}
  43. inline BigInt& operator [](const int s)
  44. {
  45. int x=s%mod;//s可能是0,边表里的需要是s+1。也可以初始化H[x]=-1。
  46. for(int i=H[x]; i; i=nxt[i])
  47. if(i==s+1) return val[s];
  48. if(!H[x]) sk[++top]=x;
  49. AE(x,s+1), sta[++tot]=s, val[s].Init();
  50. return val[s];
  51. }
  52. }f[2];
  53. inline int Get(const int s,const int bit) {return s>>(bit<<1)&3;}//s在bit位置的插头
  54. inline void Upd(int &s,int bit,int v) {bit<<=1, s|=3<<bit, s^=3<<bit, s|=v<<bit;}//将s在bit位置的插头改为v
  55. inline int Find(const int s,const int y,const int p)//找到与y位置的插头p 所对应的插头
  56. {
  57. int delta=p==1?1:-1/*向左/向右找*/,sum=delta;//if(!p) return y;
  58. for(int i=y+delta,v; ~i&&i<=m; i+=delta)//i=0~m-1!
  59. if(v=Get(s,i),sum+=v==1?1:(v==2?-1:0),!sum) return i;
  60. return -1;
  61. }
  62. void Work(const int n,const int m,const int x,const int y,Hash_Table &f,Hash_Table &g)
  63. {
  64. f.Init();
  65. for(int i=1,tot=g.tot; i<=tot; ++i)
  66. {
  67. 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;
  68. if(t1==-1||t2==-1) continue;//
  69. BigInt v=g.val[s];
  70. if(!v[0]) continue;
  71. if(!p1&&!p2) {if(x!=n&&y!=m) Upd(s,y-1,1), Upd(s,y,2), f[s]+=v;}
  72. else if(!p1&&p2)
  73. {
  74. if(y!=m) f[s]+=v;
  75. if(x!=n) Upd(s,y-1,p2), Upd(s,y,0), f[s]+=v;
  76. }
  77. else if(p1&&!p2)
  78. {
  79. if(x!=n) f[s]+=v;
  80. if(y!=m) Upd(s,y-1,0), Upd(s,y,p1), f[s]+=v;
  81. }
  82. else if(p1==1&&p2==1) Upd(s,y-1,0), Upd(s,y,0), Upd(s,t2,1), f[s]+=v;
  83. else if(p1==1&&p2==2) {if(x==n&&y==m) Ans+=v;}
  84. else if(p2==1) Upd(s,y-1,0), Upd(s,y,0), f[s]+=v;
  85. else if(p2==2) Upd(s,y-1,0), Upd(s,y,0), Upd(s,t1,2), f[s]+=v;
  86. }
  87. }
  88. int main()
  89. {
  90. int n,m; scanf("%d%d",&n,&m);
  91. if(m>n) std::swap(n,m); ::n=n, ::m=m;
  92. if(m==1) return puts("1"),0;//!
  93. int p=0; f[p].Init(), f[p][0]=1;
  94. for(int i=1; i<=n; ++i)
  95. {
  96. for(int j=1; j<=m; ++j) p^=1, Work(n,m,i,j,f[p],f[p^1]);
  97. if(i!=n)
  98. {
  99. p^=1, f[p].Init();
  100. for(int i=1,tot=f[p^1].tot,s; i<=tot; ++i)
  101. s=f[p^1].sta[i], f[p][s<<2]=f[p^1][s];
  102. }
  103. }
  104. Ans+=Ans, Ans.Print();
  105. return 0;
  106. }

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

  1. bzoj 1210 [HNOI2004] 邮递员 插头dp

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

  2. 【BZOJ1210】[HNOI2004]邮递员 插头DP+高精度

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

  3. vijos 1110小胖邮递员;bzoj 1210: [HNOI2004]邮递员

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

  4. 无聊的 邮递员 插头dp

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

  5. bzoj 2331: [SCOI2011]地板 插头DP

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

  6. 【BZOJ】2310: ParkII 插头DP

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

  7. BZOJ 2331 [SCOI2011]地板 ——插头DP

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

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

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

  9. BZOJ.1005.[HNOI2008]明明的烦恼(Prufer 高精 排列组合)

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

随机推荐

  1. Metasploit one test

    1.对Metasploit的文件结构层次做一个目录结构图 2.漏洞利用的原理及其过程 攻击者发送一个附加攻击载荷的漏洞攻击代码给存在漏洞的系统.漏洞攻击代码首先执行,如果执行成功,攻击载荷中的实际代码 ...

  2. bzoj 2190

    题意:求 题解:这题...数据范围是真小... 研究一下这一表达式,发现gcd(i,j)=1表示i,j互质,那么互质肯定能想到欧拉函数,可是欧拉函数要求j<i,那么我们变化一下:显然原矩阵是对称 ...

  3. 10进制 VS 2进制

    10进制 VS 2进制 时间限制: 1 Sec  内存限制: 32 MB 题目描述 样例输出 623 #include<stdio.h> #include<string.h> ...

  4. 性能测试四十九:ngrinder压测平台

    下载地址:https://sourceforge.net/projects/ngrinder/files/ ngrinder工作原理:这里的controller就是ngrinder平台 部署(以win ...

  5. tinymce-vue富文本编辑器(翻译)

    官方Tinymce Vue组件 翻译来自:https://github.com/tinymce/tinymce-vue 官方文档:https://www.tiny.cloud/docs/general ...

  6. 部署MySQL5.7时的权限问题

    本周部署MySQL5.7的时候遇到这样的问题,在初始化的时候,总是失败,并且报错: 2019-01-09T09:47:13.957685Z 0 [ERROR] InnoDB: Operating sy ...

  7. Jmeter中通过beanshell写入CSV的脚本

    import com.csvreader.CsvWriter; String NewDataPath=bsh.args[0]; NewDataPath=NewDataPath.replaceAll(& ...

  8. IDEA创建第一个项目详细过程

  9. #20165323 Java实验四 Android程序设计

    一.实验报告封面 课程:Java程序设计 班级:1653班 姓名:杨金川 学号:20165323 指导教师:娄嘉鹏 实验日期:2018年5月14日 实验时间:13:45 - 15:25 实验序号:实验 ...

  10. MyBatis - 1.入门

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架. MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集. MyBatis可以使用简单的XML或注解 ...