这道题属于棋盘覆盖问题的变形。
这一类问题在固定行数/列数的情况下是一类十分经典的构造dp;
不论行数/列数,这类问题一般都有明显的轮廓线概念。
同时在数据范围进一步扩大的情况下、可能还可以用矩阵来优化转移。
关于棋盘覆盖问题也有组合学公式,不过不会要求掌握。
这道题在(单纯的)状态压缩和轮廓线的意义下解法是不同的,并且本题的轮廓线解法优于一般的状态压缩。
建议在大约掌握状态压缩dp的一般解题方法之后写这道题目入门轮廓线。
状态压缩
很容易想到压缩行的状态进行转移。
每行都要填满,所以记录上一行状态是没有用的,要记录上一行覆盖了这一行哪些地方。
然后枚举这一行的可行状态,更新。
实际上状态里面记录的是上一行没有覆盖这一行的哪些地方
因为这样比起记录覆盖,可以更简单地通过位运算判可行。
注意枚举状态时候还是要枚举 0 \frak{0} 0到 L i m \frak{Lim} Lim而不能枚举可行状态
Accepted 863b
G++ 63ms 812k
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstdlib>
using namespace std;
int N,M;
long long F[12][2050]={};
bool C[2050]={};
bool check(int x)
{
int t=0;
while(x)
{
if(x&1)
{
++t;
}
else
{
if(t&1)return 0;
t=0;
}
x>>=1;
}
if(t&1)return 0;
return 1;
}
int main()
{
for(int i=0;i<(1<<11);++i)if(check(i))C[i]=1;
while(~scanf("%d%d",&N,&M))
{
if(!(N|M))return 0;
if(N<M)swap(N,M);
if((N*M)&1)
{
printf("0\n");
continue;
}
memset(F,0,sizeof(F));
for(int i=0;i<(1<<M);++i)if(check(i))F[1][i]=1;
for(int i=1;i<N;++i)
{
for(int j=0;j<(1<<M);++j)
{
for(int k=0;k<(1<<M);++k)
{
if((j|k)!=((1<<M)-1))continue;
if(!C[j&k])continue;
F[i+1][k]+=F[i][j];
}
}
}
printf("%lld\n",F[N][(1<<M)-1]);
}
return 0;
}
轮廓线
按行转移会产生许多无效的重复计算。
考虑逐格转移。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cctype>
#include<ctime>
#include<cstdlib>
using namespace std;
int n,m;
bool p;
long long F[2][2052]={};
int main()
{
while(~scanf("%d%d",&n,&m))
{
if(!n)return 0;
if((n*m)&1)
{
printf("0\n");
continue;
}
if(n<m)swap(n,m);
memset(F[0],0,sizeof(F[0 ]));
p=0; F[0][0]=1;
for(int i=0;i<n;++i)
{
for(int j=0;j<m;++j)
{
p=!p;
memset(F[p],0,sizeof(F[p]));
for(int S=0;S<(1<<m);++S)
{
if(!F[!p][S])continue;
F[p][S^(1<<j)]+=F[!p][S];
if(j&&(S&(1<<j-1))&&(!(S&(1<<j))))F[p][S^(1<<j-1)]+=F[!p][S];
}
}
}
printf("%lld\n",F[p][0]);
}
return 0;
}
数学公式
a
n
s
=
2
n
m
2
∏
i
=
1
n
∏
j
=
1
m
c
o
s
2
(
i
π
n
+
1
)
+
c
o
s
2
(
j
π
m
+
1
)
4
\frak{ans=2^{\frac{nm}{2}}\prod\limits_{i=1}^{n}\prod\limits_{j=1}^m\sqrt[4]{cos^2(\frac{i\pi}{n+1})+cos^2(\frac{j\pi}{m+1})}}
ans=22nmi=1∏nj=1∏m4cos2(n+1iπ)+cos2(m+1jπ)
具体证明我当然不会啦(
精度摆在那里,这个公式算起来不是很准的