mayoko’s diary

プロコンとかいろいろ。

yukicoder No.325 マンハッタン距離2

解法

落ち着いて場合分けをします。

頂点の数え方としては,
(第一象限の点の数) + (第二象限の点の数) + (第三象限の点の数) + (第四象限の点の数) - (x 軸の点の数) - (y 軸の点の数) + (原点の点の数)
という数え方をします。

下のソースコードでは 象限の点の数は calc 関数で, 軸の点の数は calc2 関数でやっています。

calc 関数は, 原点 (0, 0) から頂点 (x, y) までの長方形で, マンハッタン距離が d 以下の頂点数がいくつあるかを調べます。
これは, d の値で適当に場合分けすればいけます。

calc 関数を使って第一象限の(x1, y1) から (x2, y2) の長方形内の頂点数を求めることを考えます。
まず, x2 >= 0, y2 >= 0 でないとダメですね。で, dx = max(0, x1), dy = max(0, y1) とすると, calc 関数で「原点(0, 0) から」と書かれているところで, 実際には左下の頂点が どの座標かがわかります。つまり (dx, dy) から (x2, y2) への頂点数を求めれば良いわけです。
左下の頂点が (dx, dy) になったので, 原点が左下として考えるときは, 距離 d を d-dx-dy にしないといけません。これに注意して, calc 関数を使います。

第二象限以降も同じです。

ull calc(ll x, ll y, ll d) {
    ull ret = 0;
    if (d <= y) {
        if (d <= x) {
            ret = (d+2)*(d+1)/2;
        } else {
            ret = (d+d-x+2)*(x+1)/2;
        }
    } else if (d-y <= x) {
        ret = (y+1)*(d-y+1);
        if (d >= x) {
            ret += (y + d-x+1) * (x-d+y) / 2;
        } else {
            ret += y*(y+1)/2;
        }
    } else {
        ret += (y+1)*(x+1);
    }
    return ret;
}

ull calc2(ll low, ll high, ll d) {
    ll mini = max(low, -d);
    ll maxi = min(d, high);
    return maxi-mini+1;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    ll x1, y1, x2, y2, d;
    cin >> x1 >> y1 >> x2 >> y2 >> d;
    ull ans = 0;
    if (y2 >= 0 && x2 >= 0) {
        ll dx = max<ll>(0, x1);
        ll dy = max<ll>(0, y1);
        if (d-dx-dy >= 0) ans += calc(x2-dx, y2-dy, d-dx-dy);
    }
    //cout << ans << endl;
    if (y2 >= 0 && x1 <= 0) {
        ll dx = max<ll>(0, -x2);
        ll dy = max<ll>(0, y1);
        if (d-dx-dy >= 0) ans += calc(-x1-dx, y2-dy, d-dx-dy);
    }
    //cout << ans << endl;
    if (y1 <= 0 && x1 <= 0) {
        ll dx = max<ll>(0, -x2);
        ll dy = max<ll>(0, -y2);
        if (d-dx-dy >= 0) ans += calc(-x1-dx, -y1-dy, d-dx-dy);
    }
    //cout << ans << endl;
    if (y1 <= 0 && x2 >= 0) {
        ll dx = max<ll>(0, x1);
        ll dy = max<ll>(0, -y2);
        if (d-dx-dy >= 0) ans += calc(x2-dx, -y1-dy, d-dx-dy);
    }
    //cout << ans << endl;
    if (x1 <= 0 && 0 <= x2) ans -= calc2(y1, y2, d);
    //cout << ans << endl;
    if (y1 <= 0 && 0 <= y2) ans -= calc2(x1, x2, d);
    //cout << ans << endl;
    if (x1 <= 0 && 0 <= x2 && y1 <= 0 && 0 <= y2) ans--;
    cout << ans << endl;
    return 0;
}