好き!!!
問題概要
長さ の 2 つの数列 と が与えられる。
数列 であって
- 任意の に対して、
を満たすものを考えたときの、 となる の個数の最小値を求めよ。
制約
考えたこと
をなるべく変形箇所を少なくしつつ に変形して、 にオール勝ちできるようにする問題。
ここで、 の値そのものはそんなに重要じゃなくて、 と との差だけが重要 (例えば、 だったとして、これは でも状況はまったく変わらない) なので、 は全部 にしてしまう。そうすると
みたいな感じになる。これに対して、 の総和を変えずに、なるべく変更を加える箇所を少なくして、マイナスをなくす問題になる。
ただちにわかることは
- マイナスは埋め立ててすべて にしなければならない
よって、マイナスの箇所は必ず変更が加えられることになる。このとき、 の値が正の部分から削ってマイナスを埋め立てることになる。よって、正の部分を削る箇所を少なく抑えるには、なるべく値の大きなところから優先的に削って行くのがいい。
- このとき、すべての正の値を使い尽くしてもマイナスを消せなかった場合は ( の総和がマイナスの場合)
- マイナスがなかった場合は答えは
という点に注意する。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int N; cin >> N; vector<long long> A(N), B(N); for (int i = 0; i < N; ++i) cin >> A[i]; for (int i = 0; i < N; ++i) cin >> B[i]; vector<long long> plus; long long sum = 0; int num = 0; for (int i = 0; i < N; ++i) { long long dif = A[i] - B[i]; if (dif < 0) sum -= dif, ++num; else plus.push_back(dif); } if (num == 0) cout << 0 << endl; // マイナスがなかったら変更の必要なし else { int res = num; sort(plus.begin(), plus.end(), greater<long long>()); // 正の部分のうち、大きい方から優先的に削ってマイナスを埋め立てる long long p = 0; for (int i = 0; i < plus.size(); ++i) { p += plus[i]; ++res; if (p >= sum) break; } if (p >= sum) cout << res << endl; else cout << -1 << endl; } }