Codeforces 161E (263E) Rhombus
問題
nxm行列aijが与えられる。
関数x, yを
f(x, y) = Σ[i=1 to n]Σ[j=1 to m]a[i][j] * max(0, k - abs(i - x) - abs(j - y))
と定義する。
k≦x≦n - k + 1
k≦y≦m - k + 1
を満たし、f(x, y)を最小にするようなx, yの組を求めよ。
答えが複数ある場合どれを出力してもかまわない。
制約条件
n, m≦1000
2 * k≦min(n, m)
方針
累積和を使って、差分を効率的に計算する。
差分は、O(k)で求まればよい。(全体で500^3くらいの計算量になるので)
斜めの累積和を使うともっと計算量が落ちる。
ソースコード
const int MX = 1010; int h, w, k; int a[MX][MX]; ll s[MX][MX], ss[MX][MX]; inline ll calc(int y, int x, int Y, int X){ Y++; X++; return s[Y][X] - s[Y][x] - s[y][X] + s[y][x]; } int main(){ scanf("%d%d%d", &h, &w, &k); ll sum = 0; rep(i, h) rep(j, w){ scanf("%d", a[i] + j); s[i + 1][j + 1] = s[i + 1][j] + s[i][j + 1] - s[i][j] + a[i][j]; sum += (ll)a[i][j] * max(0, k - abs(i - k + 1) - abs(j - k + 1)); } ss[k - 1][k - 1] = sum; ll mxs = sum; int my = k - 1, mx = k - 1; for(int i = k - 1; i <= h - k; i++) for(int j = k - 1; j <= w - k; j++){ if(j == k - 1){ if(i == k - 1) continue; ss[i][j] = ss[i - 1][j]; rep(l, k){ ss[i][j] -= calc(i - l - 1, j - k + l + 1, i - l - 1, j + k - l - 1); ss[i][j] += calc(i + l, j - k + l + 1, i + l, j + k - l - 1); } } else{ ss[i][j] = ss[i][j - 1]; rep(l, k){ ss[i][j] -= calc(i - k + l + 1, j - l - 1, i + k - l - 1, j - l - 1); ss[i][j] += calc(i - k + l + 1, j + l, i + k - l - 1, j + l); } } if(ss[i][j] > mxs){ mxs = ss[i][j]; my = i; mx = j; } } cout << my + 1 << " " << mx + 1 << endl; return 0; }