列表

详情


NC15252. 白兔的棋盘

描述

白兔有一个n*m的棋盘,某些格子是障碍。有k种大小为x*y的矩形图案(x<=2,且矩形不能旋转),每种数量无限个。

白兔可以在棋盘上任意放置图案,要求图案不能放到障碍上,且任意两个图案不相交。问方案数。

两种方案不同为存在一个格子在一种方案中被覆盖,在另一种方案中未被覆盖或者覆盖这两个格子的图案大小或位置不同。
一个矩形正好铺满x行y列的一块区域,不能旋转

输入描述

第一行三个整数n,m,k(n,m<=15,k<=2*m)
接下来n行,每行m个整数,每个数为0或者1,1表示空格,0表示障碍
最后k行,每行两个数x,y(x<=2,y<=m),任意两对(x,y)不相同

输出描述

一个数,表示答案,对1e9+7取模

示例1

输入:

2 3 2
1 0 0
1 1 0
1 1
1 2

输出:

10

示例2

输入:

4 4 2
1 0 0 1
0 0 0 0
1 1 1 1
0 1 1 0
1 1
1 2

输出:

580

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 218ms, 内存消耗: 28920K, 提交时间: 2021-12-27 19:32:24

#include<bits/stdc++.h>
#define For(i,l,r) for(int i=l;i<=r;i++)
#define Con continue
using namespace std;
const int mod=1e9+7,N=20,SS=(1<<15);
int s[N][N],f[N][N][SS],n,m,x[N<<1],y[N<<1],k,a[N][N];
int work(int l,int r){return ((1<<r)-1)^((1<<(l-1))-1);}
bool chk(int X,int Y,int i,int S){
	if(Y+y[i]>m)return 0;
	if(X+x[i]-1>n)return 0;
	if(work(Y+1,Y+y[i])&S)return 0;
	bool ff=(s[X][Y+y[i]]-s[X][Y]==y[i]);
	if(x[i]==2)ff&=(s[X+1][Y+y[i]]-s[X+1][Y]==y[i]);
	return ff;
}
void add(int &x,int y){x=(x+y)%mod;}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    For(i,1,n)For(j,1,m){
        scanf("%d",&a[i][j]);
        s[i][j]=a[i][j]+s[i][j-1];
    }
    For(i,1,k)scanf("%d%d",&x[i],&y[i]);
    f[1][0][0]=1;
    For(i,1,n)For(j,0,m)For(S,0,(1<<m)-1){
        if(!f[i][j][S])Con;
        if(j==m){add(f[i+1][0][S],f[i][j][S]);Con;}
        if(!a[i][j+1]){add(f[i][j+1][S],f[i][j][S]);Con;}
        if(S&(1<<j)){add(f[i][j+1][S^(1<<j)],f[i][j][S]);Con;}
        add(f[i][j+1][S],f[i][j][S]);
        For(p,1,k){
            if(!chk(i,j,p,S))Con;
            if(x[p]==1)add(f[i][j+y[p]][S&(((1<<m)-1)^work(j+1,j+y[p]))],f[i][j][S]);
            else add(f[i][j+y[p]][S|work(j+1,j+y[p])],f[i][j][S]);
        }
    }
    printf("%d",f[n][m][0]);
}

上一题