【JZOJ4791】【NOIP2016提高A组模拟9.21】矩阵

题目描述

在麦克雷的面前出现了一个有n*m个格子的矩阵,每个格子用“.”或“#”表示,“.”表示这个格子可以放东西,“#”则表示这个格子不能放东西。现在他拿着一条1*2大小的木棒,好奇的他想知道对于一些子矩阵,有多少种放木棒的方案。

输入

第一行包含 2 个正整数 n,m。
接下来 n 行每行包含 m 个字符“.”或“#”。
第n+1行包含1个正整数q,表示询问次数。
接下来q行每行包含4个正整数r1,c1,r2,c2,分别表示询问的子矩阵的左上格子和右下格子的位置。

输出

输出共 q 行,每行包含 1 个整数,表示该询问的方案数。

样例输入

5 8
….#..#
.#……
##.#….
##..#.##
……..
4
1 1 2 3
4 1 4 1
1 2 4 5
2 5 5 8

样例输出

4
0
10
15

数据范围

30%:q<=100
100%:q<=10^5,1<=n,m<=500

样例解释

这里写图片描述

解法

把原问题转化为规定矩阵中有多少对相邻的“.”。
简单的前缀和问题。

代码

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#define ll long long
#define ln(x,y) int(log(x)/log(y))
#define sqr(x) ((x)*(x))
using namespace std;
const char* fin="aP2.in";
const char* fout="aP2.out";
const int inf=0x7fffffff;
const int maxn=507;
int n,m,i,j,k,l,o,ans;
char a[maxn][maxn];
int c[maxn][maxn][4],sum[maxn][maxn][7],d[maxn][maxn][4];
bool judge(int x,int y){
    return x>0 && x<=n && y>0 && y<=m && a[x][y]=='.';
}
int getsum(int sx,int sy,int tx,int ty,int kind){
    if (tx<sx || ty<sy) return 0;
    return sum[tx][ty][kind]-sum[sx-1][ty][kind]-sum[tx][sy-1][kind]+sum[sx-1][sy-1][kind];
}
int main(){
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;i++) scanf("%s",a[i]+1);
    for (i=1;i<=n;i++) for (j=1;j<=m;j++){
        if (judge(i,j)){
            if (judge(i+1,j)){
                c[i][j][0]++;
                c[i][j][1]++;
                sum[i][j][0]++;
                sum[i][j][1]++;
                sum[i][j][3]++;
                sum[i][j][4]++;
                sum[i][j][5]++;
                d[i][j][0]++;
            }
            if (judge(i,j+1)){
                c[i][j][0]++;
                c[i][j][3]++;
                sum[i][j][0]++;
                sum[i][j][2]++;
                sum[i][j][3]++;
                sum[i][j][4]++;
                sum[i][j][6]++;
                d[i][j][3]++;
            }
            if (judge(i-1,j)){
                c[i][j][2]++;
                c[i][j][3]++;
                sum[i][j][1]++;
                sum[i][j][2]++;
                sum[i][j][3]++;
                sum[i][j][4]++;
                sum[i][j][5]++;
                d[i][j][2]++;
            }
            if (judge(i,j-1)){
                c[i][j][1]++;
                c[i][j][2]++;
                sum[i][j][0]++;
                sum[i][j][1]++;
                sum[i][j][2]++;
                sum[i][j][4]++;
                sum[i][j][6]++;
                d[i][j][1]++;
            }
        }
        for (k=0;k<7;k++) sum[i][j][k]+=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k];
    }
    scanf("%d",&i);
    for (;i;i--){
        scanf("%d%d%d%d",&j,&k,&l,&o);
        if (j==l && k==o) ans=0;
        else 
        if (j==l){
            ans=getsum(j,k+1,j,o-1,6)+d[j][k][3]+d[j][o][1];
        }else if (k==o) ans=getsum(j+1,o,l-1,o,5)+d[j][o][0]+d[l][o][2];
        else {
            ans=getsum(j+1,k+1,l-1,o-1,4)+c[j][k][0]+c[j][o][1]+c[l][k][3]+c[l][o][2];
            ans+=getsum(j,k+1,j,o-1,0)+getsum(l,k+1,l,o-1,2);
            ans+=getsum(j+1,o,l-1,o,1)+getsum(j+1,k,l-1,k,3);
        }
        ans/=2;
        printf("%d
",ans);
    }
    return 0;
}

启发

注意边界。

原文地址:https://www.cnblogs.com/hiweibolu/p/6714894.html