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\n",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;
}

 

posted on 2019-04-17 22:22  Narh  阅读(108)  评论(0编辑  收藏  举报

导航