裏紙

ほぼ競プロ、たまに日記

SRM 660 Div1 Easy - Coversta

問題

TopCoder Statistics - Problem Statement

問題概要

nm列のグリッドaが与えられる.各グリッドの中には0~9のいずれかの数字が書かれている.そして,stationを(i,j)に設置すると,(i+x_k, j+y_k ) ( 1 \le k \le z)内に書かれている数字の合計をポイントとして得ることが出来る.

今,stationを2つ設置しようと考える.仮に両方のstationが同じグリッドをカバーした時の点数は1回分としてしか数えない(つまり2つのstationがカバーするグリッドの和集合が得られるポイントになる).そのときに得られる得点の最大値を答えよ.

  •  1 \le n \le 100
  •  1 \le m \le 100
  •  1 \le z \le 10

イデア

2つのstationの領域が被ってしまう時にどうすればいいかとかいうことを考えると効率的な方法が思いつけなかった.Editorialを見ながら.

1つ目のstationを固定して考えよう.すると,そのstationによってカバーされるグリッドの個数はたかだかz個になる.そして,1つ目の設置されたstationに対応するある座標(X,Y)に対して,2つ目のstationを設置した時にその2つ目のstationが(X,Y)をカバーしてしまう2つ目のstationの設置方法はたかだかz個存在する.つまり,1つ目のstationによってカバーされるたかだかz個のグリッドを,2つ目のstationの設置によってカバーしてしまう可能性というのは組み合わせを考えればたかだかz^2箇所になる.

つまり,まず1つ目のstationの位置を全探索する.その中で,被る可能性のあるたかだかz^2箇所を調べ,2つ目のstationを設置することによって得られるポイントを逐次更新していく(正確には,被っている部分を引いていく).

それが全ての座標に対して終われば,その1つ目のstation固定に関しての2つ目のstationによって得られる得点が確定するので,2つ目のstationの位置を全探索しながら得られる得点の最大値を更新していく.

実装(C++)

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define each(itr,c) for(__typeof(c.begin()) itr=c.begin(); itr!=c.end(); ++itr)
#define all(x) (x).begin(),(x).end()
#define mp make_pair
#define pb push_back
#define fi first
#define se second

typedef vector<int> vi;
typedef vector<vi> vvi;

class Coversta {
    public:
    int X,Y;
    inline bool in(int x, int y)
    {
        return(0<=x&&x<X && 0<=y&&y<Y);
    }

    int place(vector<string> a, vector<int> x, vector<int> y) {
        X=a.size();
        Y=a[0].size();

        int z=x.size();

        //1つ目のstation設置によって得られるpoint
        vvi sum1(X,vi(Y,0));
        rep(i,X)rep(j,Y)rep(k,z)
        {
            int nx=i+x[k], ny=j+y[k];
            if(in(nx,ny)) sum1[i][j]+=(a[nx][ny]-'0');
        }

        int ret=0;
        //1つ目のstationの位置を固定
        rep(i,X)rep(j,Y)
        {
            //2つ目のstation設置によって得られるpoint
            vvi sum2=sum1;

            //1つ目のstationのp個目のグリッドと
            //2つ目のstationのq個目のグリッドが
            //重なっていると仮定した時
            rep(p,z)
            {
                int nx=i+x[p], ny=j+y[p];
                if(in(nx,ny))
                {
                    rep(q,z)
                    {
                        int nnx=nx-x[q], nny=ny-y[q];
                        if(in(nnx,nny)) sum2[nnx][nny]-=(a[nx][ny]-'0');
                    }
                }
            }

            //1つ目のstationの固定に対してベストな位置を選択
            rep(k,X)rep(l,Y) ret=max(ret,sum1[i][j]+sum2[k][l]);
        }

        return ret;
    }
};