這樣的棋盤地圖容易讓人想到插頭dp
我們可以設(shè)計兩種插頭:還沒拐過彎的插頭((#1)和拐過彎的插頭(#2),這樣每個插頭就可以用一個三進制數(shù)存儲,為了壓位方便我們用4進制
考慮輪廓線dp時候的轉(zhuǎn)移,設(shè)當前格子的左方插頭為plug1,上方插頭為plug2,有以下幾種轉(zhuǎn)移(為了方便,這里只討論plug1<=plug2的情況,反過來是一樣的)
- plug1=0,plug2=0
有三種轉(zhuǎn)移:向左邊新建一個#1插頭;向下邊新建一個#1插頭;以這個格子為拐點,向上面和下面同時新建一個#2插頭 - plug1=0,plug2=1
有兩種轉(zhuǎn)移:上面的插頭繼續(xù)向下延伸,即向下的#1插頭,或者在這里拐彎,即向右的#2插頭 - plug1=0,plug2=2
有兩種轉(zhuǎn)移:上面的插頭繼續(xù)向下延伸,即向下的#2插頭,或者在這個格子結(jié)束,沒有插頭 - plug1=1,plug2=1
只有一種情況:這兩個半截在這個格子會合,當前格子沒有插頭
很開心,就這么多
要注意幾個細節(jié):
- 如果這個格子是障礙物,那么只有plug1=0 && plug2=0的時候才能轉(zhuǎn)移
- 轉(zhuǎn)移的時候要注意“是否能向下/右延伸,即判斷一下是否到了邊界或者有障礙
行與行之間的轉(zhuǎn)移是套路轉(zhuǎn)移
#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];
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;
}
總結(jié)
以上是生活随笔為你收集整理的BZOJ2331: 地板 题解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。