CF上是输出任意一个方案,这题改成了输出方案数。
其实用一个六维DP很显然的。但很麻烦。
考虑优化一下暴搜。
以为行数最多只有5行,所以可以枚举每列的状态然后再判断行的状态。
所以要先预处理每列要使值为x的所有状态。
然后把得出的一行的状态hash一下,记忆化一下,设f[x][y][z]表示做到第x列,x-1列的状态是y,现在的hash值是z,如果这个状态不为-1(初始状态为-1,表示没出现过),那么直接退出f[x][y][z]。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=21,mo=1000000007;
int i,j,k,l,t,n,m,ans;
int hang[maxn],lie[maxn],shu[1000][1000];
int ci[11],er[11],f[21][32][170000],a[21];
//bool bz[21][32][170000];
int dfs(int x,int y){
int t=0,i;
fo(i,1,n)t+=a[i]*ci[i-1];
if(x==m+1){
fo(i,1,n)if(a[i]!=hang[i])return 0;
return 1;
}
if(f[x][y][t]>=0)return f[x][y][t];
f[x][y][t]=0;
fo(i,1,n){
if(a[i]>hang[i]||a[i]+(m-x+2)/2
}
fo(i,1,shu[lie[x]][0]){
fo(j,1,n)if(!(y&er[j])&&(shu[lie[x]][i]&er[j]))a[j]++;
f[x][y][t]=(f[x][y][t]+dfs(x+1,shu[lie[x]][i]))%mo;
fo(j,1,n)if(!(y&er[j])&&(shu[lie[x]][i]&er[j]))a[j]--;
}
return f[x][y][t];
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,n)scanf("%d",&hang[i]);
fo(i,1,m)scanf("%d",&lie[i]);ci[0]=1;
fo(i,1,n)er[i]=1<
fo(i,0,(1<
int u=0;
fo(j,1,5)if((er[j]&i)&&(!(er[j-1]&i)))u++;
shu[u][++shu[u][0]]=i;
}
memset(f,255,sizeof(f));
printf("%d\n",dfs(1,0));
}