SRM623 Div1Easy UniformBoard

問題概要
'P'のみで作られる長方形区間の面積の最大値を求めよ。ただし、K回まで 'A' または 'P' を取って '.'(空) に置く操作ができる。

解法
1. 全ての 'A', 'P', '.' の数を数える。
2. 全ての長方形Rを全探索する。
3-1. '.' が全体の正方形のグリッドに一つも存在しないとき
 Rの中の 'A' の数がRの面積に一致するなら最大値を更新。
3-2. '.' が全体の正方形のグリッドに一つでも存在するなら
 「(Rの面積 - R内の林檎の数) が R外にある」かつ「R内の 'P' の数 * 2(退ける操作と 'A' を持ってくる操作) + R内の '.' の数 <= K」 ならば、最大値を更新する。

#define REP(i,a,b) for(int i=a;i<b;i++)
#define rep(i,n) REP(i,0,n)
class UniformBoard {
public:
  void summation(const vector<string> &board, int sum[][21], int N, char ch) {
    rep(i, N) rep(j, N) {
      sum[i+1][j+1] = sum[i+1][j] + sum[i][j+1] - sum[i][j] + (board[i][j] == ch);
    }
  }
  
  int getSum(int sum[][21], int i, int j, int k, int l) {
    return sum[k][l] - sum[i][l] - sum[k][j] + sum[i][j];
  }
  
  int getBoard(vector <string> board, int K) {
    const int N = board.size();
    int cntAllA = 0, cntAllP = 0, cntAllE;
    rep(i, N) rep(j, N) {
      cntAllA += board[i][j] == 'A';
      cntAllP += board[i][j] == 'P';
    }
    cntAllE = N*N-cntAllA-cntAllP;

    int sumA[21][21] = {}; summation(board, sumA, N, 'A');
    int sumP[21][21] = {}; summation(board, sumP, N, 'P');
    int sumE[21][21] = {}; summation(board, sumE, N, '.');
    
    int ans = 0;
    
    if(cntAllE == 0) {
      rep(i, N) rep(j, N) {
        REP(k, i+1, N+1) REP(l, j+1, N+1) {
          int numA = getSum(sumA, i, j, k, l);
          int area = (k-i)*(l-j);
          if(numA == area) ans = max(ans, area);
        }
      }
      return ans;
    }
    
    rep(i, N) rep(j, N) {
      REP(k, i+1, N+1) REP(l, j+1, N+1) {
        int numP = getSum(sumP, i, j, k, l);
        int numE = getSum(sumE, i, j, k, l);
        int area = (k-i)*(l-j);
        
        if(area > cntAllA) continue;
        if(numP*2 + numE > K) continue;
        ans = max(ans, area);
      }
    }
    
    return ans;
  }
};