做这个题前前后后磨了3天,感觉自己弱爆了;总算理解好了,不过收获也很大,发现之前状态理解错了,做这个题的时候,发现论文里面的状态转移完全无法理解,然后去找各种解题报告,让我恍然大悟的一句话是:“因为已经做到了第i行,那么i-1行一定要求是满的。”,这是在Wrongswer空间看到的一句话,对于dfs中pre,now状态转换顿时就明白了。而且这个解题报告状态的解释也很清楚,值得一看。为了加深自己的理解,就写了个反状态的压缩,dfs的时候思考清楚就好了,预处理做好了接下来的就跟之前的题目一样一样了。还有一点,题目空间给的小,存储状态的数组不要开太大,否则会MEL。
ACcode:
#include<cstdio>
#include<cstring>
typedef long long LL;
const int NS=79248;
const int LIM=1<<9;
LL dp[2][LIM];
int state[NS][2],top;
void dfs(int pre,int now,int pf,int nf,int pos)
{
if (pos==0)
{
if (pf&&nf)
state[top][0]=pre,
state[top++][1]=now;
return ;
}
dfs((pre<<1|1)-pf,(now<<1)+nf,1,1,pos-1); //不放
if (pf&&nf)
dfs(pre<<1|1,now<<1,1,1,pos-1), //竖直放
dfs(pre<<1|1,now<<1,0,1,pos-1), //缺右下
dfs(pre<<1|1,now<<1,1,0,pos-1); //缺右上
if (nf)
dfs((pre<<1|1)-pf,now<<1,0,0,pos-1); //缺左上
if (pf)
dfs(pre<<1|1,(now<<1)+nf,0,1,pos-1), //横放
dfs(pre<<1|1,(now<<1)+nf,0,0,pos-1); //缺左下
}
void init(int x)
{
for (int i=0; i<LIM; i++)
dp[x][i]=0;
}
void print(int x,int y)
{
for (int i=0; i<y; i++)
printf("%d",(x>>i)&1);
}
int main()
{
int n,m,p,q,s;
while (~scanf("%d %d",&n,&m))
{
init(0),top=s=0;
if (n<m) n^=m,m^=n,n^=m;
dp[0][(1<<m)-1]=1,dfs(0,0,1,1,m);
for (int i=0; i<n; i++)
{
s^=1,init(s);
for (int j=0; j<top; j++)
p=state[j][0],q=state[j][1],
dp[s][q]+=dp[s^1][p];
}
printf("%I64d\n",dp[s][(1<<m)-1]);
}
return 0;
}