题目大概说给一个n*m个格子,格子'.'表示可以放东西,多次询问矩形区域(x1,y1)-(x2,y2)有几种放一张1*2的骨牌的方案数。
分别考虑横着竖着放,预处理出二维的前缀和,即sum[x][y]表示(1,1)-(x,y)的横着或者竖着放的方案数,然后对于每一个询问就拆成几个前缀和容斥一下。。
细节要注意。。骨牌是1*2的。。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 char map[555][555]; 5 int hsum[555][555],vsum[555][555]; 6 int main(){ 7 int n,m; 8 scanf("%d%d",&n,&m); 9 for(int i=1; i<=n; ++i){ 10 for(int j=1; j<=m; ++j){ 11 scanf(" %c",&map[i][j]); 12 } 13 } 14 15 for(int i=1; i<=n; ++i){ 16 for(int j=2; j<=m; ++j){ 17 int t=(map[i][j]=='.' && map[i][j-1]=='.'); 18 if(i==0){ 19 hsum[i][j]=hsum[i][j-1]+t; 20 }else{ 21 hsum[i][j]=hsum[i][j-1]+hsum[i-1][j]-hsum[i-1][j-1]+t; 22 } 23 } 24 } 25 for(int i=2; i<=n; ++i){ 26 for(int j=1; j<=m; ++j){ 27 int t=(map[i][j]=='.' && map[i-1][j]=='.'); 28 if(j==0){ 29 vsum[i][j]=vsum[i-1][j]+t; 30 }else{ 31 vsum[i][j]=vsum[i][j-1]+vsum[i-1][j]-vsum[i-1][j-1]+t; 32 } 33 } 34 } 35 36 int q,x1,y1,x2,y2; 37 scanf("%d",&q); 38 while(q--){ 39 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 40 int res=hsum[x2][y2]-hsum[x2][y1]-hsum[x1-1][y2]+hsum[x1-1][y1]; 41 res+=vsum[x2][y2]-vsum[x2][y1-1]-vsum[x1][y2]+vsum[x1][y1-1]; 42 printf("%d\n",res); 43 } 44 return 0; 45 }