BZOJ2331: 地板 题解

这样的棋盘地图容易让人想到插头dp
我们可以设计两种插头:还没拐过弯的插头((#1)和拐过弯的插头(#2),这样每个插头就可以用一个三进制数存储,为了压位方便我们用4进制
考虑轮廓线dp时候的转移,设当前格子的左方插头为plug1,上方插头为plug2,有以下几种转移(为了方便,这里只讨论plug1<=plug2的情况,反过来是一样的)

  • plug1=0,plug2=0
    有三种转移:向左边新建一个#1插头;向下边新建一个#1插头;以这个格子为拐点,向上面和下面同时新建一个#2插头
  • plug1=0,plug2=1
    有两种转移:上面的插头继续向下延伸,即向下的#1插头,或者在这里拐弯,即向右的#2插头
  • plug1=0,plug2=2
    有两种转移:上面的插头继续向下延伸,即向下的#2插头,或者在这个格子结束,没有插头
  • plug1=1,plug2=1
    只有一种情况:这两个半截在这个格子会合,当前格子没有插头
    很开心,就这么多
    要注意几个细节:
    1. 如果这个格子是障碍物,那么只有plug1=0 && plug2=0的时候才能转移
    2. 转移的时候要注意“是否能向下/右延伸,即判断一下是否到了边界或者有障碍
      行与行之间的转移是套路转移
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;

const int MOD=20110520;
const LL LINF=2e16;
const int INF=1e9;
const int magic=348;
const double eps=1e-10;
const int hashmod=4841;

inline int getint()
{
    char ch;int res;bool f;
    while (!isdigit(ch=getchar()) && ch!='-') {}
    if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
    while (isdigit(ch=getchar())) res=res*10+ch-'0';
    return f?res:-res;
}

int n,m;
char a[148][148],tmp[148][148];

struct Hash
{
    vector<Pair> hsh[5048];
    inline void init()
    {
        for (register int i=0;i<=hashmod-1;i++)
            hsh[i].clear();
    }
    inline void Insert(int Mask,int newval)
    {
        int h=Mask%hashmod;newval%=MOD;
        for (register int i=0;i<int(hsh[h].size());i++)
            if (hsh[h][i].x==Mask) {hsh[h][i].y+=newval%=MOD;return;}
        hsh[h].pb(mp(Mask,newval));
    }
}dp[2];

//plug=0: no plug
//plug=1: a plug before turning
//plug=2: a plug after turning
inline int getplug(int Mask,int pos) {return (Mask>>((pos-1)<<1))&3;}
inline int Set(int Mask,int pos,int newplug) {Mask|=(3<<((pos-1)<<1));Mask^=((3-newplug)<<((pos-1)<<1));return Mask;}

int main ()
{
    int i,j,x,y,Mask,curval,toMask,toval,plug1,plug2;n=getint();m=getint();
    for (i=1;i<=n;i++) scanf("%s",a[i]+1);
    if (n<m)
    {
        swap(n,m);
        for (i=1;i<=n;i++)
            for (j=1;j<=m;j++)
                tmp[i][j]=a[m-j+1][i];
        for (i=1;i<=n;i++)
            for (j=1;j<=m;j++)
                a[i][j]=tmp[i][j];
    }
    dp[0].init();dp[1].init();
    dp[0].Insert(0,1);int cur=1,pre=0;
    for (x=1;x<=n;x++)
    {
        for (y=1;y<=m;y++)
        {
            dp[cur].init();
            for (i=0;i<=hashmod-1;i++)
                for (j=0;j<int(dp[pre].hsh[i].size());j++)
                {
                    Mask=dp[pre].hsh[i][j].x;curval=dp[pre].hsh[i][j].y;
                    plug1=getplug(Mask,y);plug2=getplug(Mask,y+1);
                    if (a[x][y]=='*')
                    {
                        if (!plug1 && !plug2) dp[cur].Insert(Mask,curval);
                    }
                    else
                    {
                        if (!plug1 && !plug2)
                        {
                            if (x!=n && a[x+1][y]=='_' && y!=m && a[x][y+1]=='_') toMask=Set(Set(Mask,y,2),y+1,2),dp[cur].Insert(toMask,curval);
                            if (x!=n && a[x+1][y]=='_') toMask=Set(Mask,y,1),dp[cur].Insert(toMask,curval);
                            if (y!=m && a[x][y+1]=='_') toMask=Set(Mask,y+1,1),dp[cur].Insert(toMask,curval);
                        }
                        if (plug1==1 && !plug2)
                        {
                            if (y!=m && a[x][y+1]=='_') toMask=Set(Set(Mask,y,0),y+1,1),dp[cur].Insert(toMask,curval);
                            if (x!=n && a[x+1][y]=='_') toMask=Set(Mask,y,2),dp[cur].Insert(toMask,curval);
                        }
                        if (plug1==2 && !plug2)
                        {
                            if (y!=m && a[x][y+1]=='_') toMask=Set(Set(Mask,y,0),y+1,2),dp[cur].Insert(toMask,curval);
                            toMask=Set(Mask,y,0);dp[cur].Insert(toMask,curval);
                        }
                        if (!plug1 && plug2==1)
                        {
                            if (x!=n && a[x+1][y]=='_') toMask=Set(Set(Mask,y,1),y+1,0),dp[cur].Insert(toMask,curval);
                            if (y!=m && a[x][y+1]=='_') toMask=Set(Mask,y+1,2),dp[cur].Insert(toMask,curval);
                        }
                        if (plug1==1 && plug2==1)
                        {
                            toMask=Set(Set(Mask,y,0),y+1,0);dp[cur].Insert(toMask,curval);
                        }
                        if (!plug1 && plug2==2)
                        {
                            if (x!=n && a[x+1][y]=='_') toMask=Set(Set(Mask,y,2),y+1,0),dp[cur].Insert(toMask,curval);
                            toMask=Set(Mask,y+1,0);dp[cur].Insert(toMask,curval);
                        }
                    }
                }
            swap(cur,pre);
        }
        if (i==n) continue;
        dp[cur].init();
        for (i=0;i<hashmod;i++)
            for (j=0;j<int(dp[pre].hsh[i].size());j++)
            {
                Mask=dp[pre].hsh[i][j].x;curval=dp[pre].hsh[i][j].y;
                dp[cur].Insert(Mask<<2,curval);
            }
        swap(cur,pre);
    }
    for (i=0;i<int(dp[pre].hsh[0].size());i++)
        if (dp[pre].hsh[0][i].x==0) {printf("%d\n",dp[pre].hsh[0][i].y);return 0;}
    printf("0\n");return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值