NC15252. 白兔的棋盘
描述
白兔有一个n*m的棋盘,某些格子是障碍。有k种大小为x*y的矩形图案(x<=2,且矩形不能旋转),每种数量无限个。
白兔可以在棋盘上任意放置图案,要求图案不能放到障碍上,且任意两个图案不相交。问方案数。
输入描述
第一行三个整数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]); }