zoukankan      html  css  js  c++  java
  • bzoj 1814 Ural 1519 Formula 1 ——插头DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1814

    普通的插头 DP 。但是调了很久。注意如果合并两个 1 的话,不是 “把向右第一个 2 该成 1 ”,而是 “把向右第一个没有与 1 匹配的 2 改成 1 ”。

    原来获取哈希值是用字符串哈希的方法,遍历12个位置;太慢。直接对某数取模作为哈希值,手写哈希表保证不会找错状态。大概 1e5 个状态?

    在转移的时候看一下下方和右边有没有障碍、只做合法的转移的话,取答案的时候就不用在判断 “当前两个位置是 1 和 2 ”之外再判断 “其余位置都是 0 ” 了。

    自己写的是 “如果当前位置是结束位置且当前两个插口是 1 和 2 就输出答案并 break ” 。这样无解的时候要手动输出 0 。

    滚动数组。并且只遍历有效的状态。方法是用手写队列存 “得到转移” 的状态,用 vis 判断该状态是否已经在队列里;把下一层的队列做好之后,遍历下一层(不是这一层)的队列把 vis 清空即可。

    注意 long long 。

    哈希表的映射方式是:原状态 -> 哈希值 -> ++tot 地分配空间 -> 原状态 。“ -> ” 就是要记下的对应关系。因为哈希值要用数组记它对应哪个位置,所以哈希值不宜太大。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=15,M=1e5+5;//mention
    int n,m,bin[N],q[2][M],t[2]; ll dp[2][M];
    bool b[N][N],vis[M],en[N][N];
    namespace H{
      const int md=1e6+3;//
      int hd[md+5],xnt,nxt[M],vl[M];
      int Ps(int s)
      {
        int h=s%md;
        for(int i=hd[h];i;i=nxt[i])
          if(vl[i]==s){return i;}
        vl[++xnt]=s; nxt[xnt]=hd[h]; hd[h]=xnt;
        return xnt;
      }
    }
    int get(int cr,int j){ return (cr&(bin[j+1]-bin[j]))>>(2*j);}
    void cz(int d,bool v){ if(!vis[d]) vis[d]=1,q[v][++t[v]]=d;}
    void solve()
    {
      bin[0]=1; int lm=m+1;
      for(int i=1;i<=lm;i++)bin[i]=bin[i-1]<<2;
      bool flag=0;
      for(int i=n;i&&!flag;i--)
        for(int j=m;j;j--)
          if(!b[i][j]){en[i][j]=flag=1;break;}
      bool u=0,v=1; flag=0;
      dp[u][H::Ps(0)]=1; q[u][++t[u]]=1;
      for(int i=1;i<=n;i++)
        {
          for(int j=1;j<=m;j++)
        {
          for(int c=1;c<=t[u];c++)
            {
              int cr=H::vl[q[u][c]];ll tp=dp[u][q[u][c]];//ll!!!
              int d0=get(cr,j-1), d1=get(cr,j), t0,t1;
              if(b[i][j])
            {
              if(!d0&&!d1)
                { t0=H::Ps(cr); cz(t0,v); dp[v][t0]+=tp;}
              continue;
            }
              if(en[i][j])
            {
              if(d0==1&&d1==2)
                { printf("%lld
    ",tp);flag=1;break;}
              continue;
            }
              if((!d0&&d1)||(!d1&&d0))
            {
              t0=cr; t1=cr+d1*bin[j-1]-d0*bin[j-1]+d0*bin[j]-d1*bin[j];
              if(i<n&&!b[i+1][j])
                {if(d0){t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp;}
                  else{t1=H::Ps(t1); cz(t1,v); dp[v][t1]+=tp;}}
              if(j<m&&!b[i][j+1])
                {if(d0){t1=H::Ps(t1); cz(t1,v); dp[v][t1]+=tp;}
                  else{t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp;}}
              continue;
            }
              if(!d0&&!d1&&i<n&&j<m&&!b[i+1][j]&&!b[i][j+1])
            {
              t0=cr+bin[j-1]+2*bin[j];
              t0=H::Ps(t0); cz(t0,v);
              dp[v][t0]+=tp; continue;
            }
              if(d0==1&&d1==1)
            {
              t0=cr-bin[j-1]-bin[j];
              for(int p=j+1,top=0,d;p<=m;p++)
                {
                  d=get(t0,p);
                  if(d==1)top++; else if(d==2&&top)top--;
                  else if(d==2){t0-=bin[p];break;}
                }
              t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp; continue;
            }
              if(d0==2&&d1==2)
            {
              t0=cr-2*bin[j-1]-2*bin[j];//2*!!!
              for(int p=j-2,top=0,d;p>=0;p--)
                {
                  d=get(t0,p);
                  if(d==2)top++; else if(d==1&&top)top--;
                  else if(d==1){t0+=bin[p];break;}
                }
              t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp;
              continue;
            }
              if(d0==2&&d1==1)
            {
              t0=cr-2*bin[j-1]-bin[j];
              t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp; continue;
            }
            }
          if(flag)break;
          for(int c=1;c<=t[u];c++)dp[u][q[u][c]]=0;
          for(int c=1;c<=t[v];c++)vis[q[v][c]]=0;//v not u!!!
          t[u]=0; swap(u,v);
        }
          if(flag)break;
          for(int c=1;c<=t[u];c++)
        {
          int cr=H::vl[q[u][c]];ll tp=dp[u][q[u][c]];//ll!!!
          if(get(cr,m))continue;
          int d=cr<<2;
          d=H::Ps(d); cz(d,v); dp[v][d]=tp;
        }
          for(int c=1;c<=t[u];c++)dp[u][q[u][c]]=0;
          for(int c=1;c<=t[v];c++)vis[q[v][c]]=0;
          t[u]=0; swap(u,v);
        }
      if(!flag)puts("0");///
    }
    int main()
    {
      scanf("%d%d",&n,&m); char ch[N];
      for(int i=1;i<=n;i++)
        {
          scanf("%s",ch+1);
          for(int j=1;j<=m;j++)
        b[i][j]=(ch[j]=='*');
        }
      solve();
      return 0;
    }
  • 相关阅读:
    读书笔记:HTML5的Doctype
    2017/09/06~2017/09/10:算法练习小记
    (分治)7617:输出前k大的数
    (递归)7215:简单的整数划分问题
    (递归)2106:Boolean Expressions
    (递归)8758:2的幂次方表示
    (递归)1750:全排列
    (枚举)8469:特殊密码锁
    关于使用unigui、webxone、mysql的几个问题
    DELPHI-Delphi常用类型及定义单元
  • 原文地址:https://www.cnblogs.com/Narh/p/10726681.html
Copyright © 2011-2022 走看看