mayoko’s diary

プロコンとかいろいろ。

SRM 507 div1 med:CubePacking

本番出したのは計算量の見積もりが甘くてclimpetさんにギリギリまで追い込まれました。

解法

B = Nc + Nb * L^3とします。最低でもこの体積分は必要です。
また,実は調べるべき体積はBからB+L^3で抑えられることもわかります(L^3をNb個縦に並べると考える)。
よって,意外に調べる範囲は大したことないのであとは体積Vに対してVですべての立方体が収まるかどうかを判定できれば嬉しいです。ということでこれをそこそこ高速で判定できれば勝ちです。

そのためには,V = a*b*cとなるa, b, cについて
(a/L) * (b/L) * (c/L) >= Nb
が成り立てば良いです。これを調べるためにVの約数を列挙して対応を調べます。

int ns, nb, l;
ll start;

bool ok(ll v) {
    vector<ll> div;
    for (ll i = 1; i * i <= v; i++) {
        if (v%i == 0) {
            div.push_back(i);
            if (i*i != v) div.push_back(v/i);
        }
    }
    int m = div.size();
    sort(div.begin(), div.end());
    for (int i = 0; i < m; i++) {
        for (int j = i; j < m; j++) {
            ll tmp = v/div[i]/div[j];
            if (div[i]*div[j]*tmp != v) continue;
            ll p = div[i]/l;
            ll q = div[j]/l;
            ll r = tmp/l;
            if (p*q*r >= nb) return true;
        }
    }
    return false;
}

class CubePacking {
public:
    int getMinimumVolume(int Ns, int Nb, int L) {
        ns = Ns, nb = Nb, l = L;
        ll V = (ll)L*L*L;
        start = V*Nb + Ns;
        for (ll v = start; ; v++) {
            if (ok(v)) return v;
        }
    }
};