前缀和 Codeforces611C New Year and Domino

传送门:点击打开链接

题意:告诉你一个地图(5e2*5e2),里面有障碍物,现在告诉你地图里面的一个子矩阵的对角点坐标,求这个子矩阵里能放多少个1*2的多米诺牌

思路:求dp[i][j]表示(1,1)到(i,j)这个子矩阵的的答案,A[i][j]表示第i行的前j列的答案,b[i][j]表示第i列的前j行的答案

那么对于(bx,by),(ex,ey),答案就等于dp[ex][ey]-dp[ex][by]-dp[bx][ey]+dp[bx][by]+A[bx][ey]-A[bx][by-1]+B[by][ex]-B[by][bx-1]

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define fuck(x) cout<<"["<PII;

const int MX = 500 + 2;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int n, m;
char s[MX][MX];
int dp[MX][MX], A[MX][MX], B[MX][MX];

void prosolve() {
    memset(dp, 0, sizeof(dp));
    memset(A, 0, sizeof(A));
    memset(B, 0, sizeof(B));

    for(int ex = 1; ex <= n; ex++) {
        int cnt = 0;
        for(int ey = 1; ey <= m; ey++) {
            if(1 < ey && s[ex][ey] == '.' && s[ex][ey - 1] == '.') cnt++;
            if(1 < ex && s[ex][ey] == '.' && s[ex - 1][ey] == '.') cnt++;
            dp[ex][ey] = dp[ex - 1][ey] + cnt;
        }
    }

    for(int ex = 1; ex <= n; ex++) {
        for(int ey = 1; ey <= m; ey++) {
            A[ex][ey] = A[ex][ey - 1];
            if(1 < ey && s[ex][ey] == '.' && s[ex][ey - 1] == '.') A[ex][ey]++;
        }
    }

    for(int ey = 1; ey <= m; ey++) {
        for(int ex = 1; ex <= n; ex++) {
            B[ey][ex] = B[ey][ex - 1];
            if(1 < ex && s[ex][ey] == '.' && s[ex - 1][ey] == '.') B[ey][ex]++;
        }
    }
}

int main() {
    //FIN;
    while(~scanf("%d%d", &n, &m)) {
        for(int i = 1; i <= n; i++) {
            scanf("%s", s[i] + 1);
        }
        prosolve();

        int Q; scanf("%d", &Q);
        while(Q--) {
            int bx, by, ex, ey;
            scanf("%d%d%d%d", &bx, &by, &ex, &ey);
            int ans = dp[ex][ey] - dp[ex][by] - dp[bx][ey] + dp[bx][by];
            ans += A[bx][ey] - A[bx][by];
            ans += B[by][ex] - B[by][bx];
            printf("%d\n", ans);
        }
    }
    return 0;
}


你可能感兴趣的:(ACM_前缀和)