[ARC139] B - Make N

[Q] https://atcoder.jp/contests/arc139/tasks/arc139_b

0. 1<A<Bにしたいので、A>Bならswapしちゃう。
1. 貪欲的に考えるととりあえず次の5パターンがすぐわかる。
(a) 全部1
(b) A>B>1でとる(Aで取り切れるだけとる)
(c) A>1 でとる(Aで取り切れるだけとる)
(d) B>A>1でとる(Bで取り切れるだけとる)
(e) B>1でとる(Bで取り切れるだけとる)

2. 残りのパターンが一番厄介。
(f) AとBをバランスよくとって、1を極力減らす。(探索)
これは、1のコストが高くて、AとBのコストがいい感じに低いとき。

3. まず、AとBの最小公倍数(LCM)でループするのがわかる。ループ部分は、1周だけ残して、1,A,Bのどれか最高効率で確定しちゃっていい。
なので、NがLCM+N%LCMにまず減らせる。

Q. LCM1周だけ残す?

N=36, A=5, B=7, 1のコストがとても高いときを考える。

LCM = 5*7 = 35
もしLCMを全部とってしまうと、
N % 35 = 1で、1を1個とってしまう。

けど、
N = 3*5 + 3*7 = 36
1をとらない取り方がありうる。これを漏らしたくないので、35を残しておく。

Q. LCMは1週で足りる?
35を7で割ると5つにわけられる
7%5 = 2
14%5 = 4
21%5 = 1
28%5 = 3
35%5 = 0

あまりは、1のコストで採用しないといけない個数。
剰余を網羅できるのがLCMなので、1週あれば足りる。

4. Bの取り方を、0個、1個、... B/N個と探索する。
2パターンみた。
(a) B>A>1(Bを規定数とったあと、Aをできるだけとる)
(b) B>1 (Bを規定数とったあと、1をできるだけとる)

この6パターンの最小値がこたえ。

実装

int main() {
 cincout();

 ll T;
 cin >> T;
 ll N, A, B, X, Y, Z;
 ll p;
 rep(i, T) {
   cin >> N >> A >> B >> X >> Y >> Z;
   if (A > B) {  // 1<A<Bにする
     swap(A, B);
     swap(Y, Z);
   }
   // 全部1
   ll ans = N * X;
   // loopを確定させる
   ll g = gcd(A, B);
   ll must = 0;
   ll LCM = A * B / g;
   ll loop = N / LCM - 1;  // LCM1週だけ残して、AとBのバランス調整する
   if (loop > 0) {              // loop箇所は最高効率で処理
     ll div = loop * LCM;       // 確定させる分
     must = div * X;            // 全部1でとる
     chmin(must, div / A * Y);  // 全部Aでとる
     chmin(must, div / B * Z);  // 全部Bでとる
     N -= div;                  // あまり+LCMで調整分まで減らす
   }
   // のこりはloop+端数
   rep(b, N / B + 1) {  // Bでとれる個数を探索する。
                        // いずれにせよroot(N)くらいまで減るはず
     ll cand1 = 0;      // b>1をできるだけ
     ll cand2 = 0;      // b>a>1をできるだけ
     ll n = N - b * B;  // のこり
     cand1 = b * Z + n * X; // b>1
     cand2 = b * Z + (n / A) * Y + (n % A) * X; // b>a>1
     chmin(ans, cand1 + must);
     chmin(ans, cand2 + must);
   }
   cout << ans << endl;
 }
}

https://atcoder.jp/contests/arc139/submissions/31243544

いいなと思ったら応援しよう!