実行時間制限: 2 sec / メモリ制限: 1024 MB / Difficulty: 926
問題概要
「1週間」を1日目から 日目までを休日、
日目から
日目までを平日とした、
日間で定義する。また、
個の予定があり、
番目の予定は今日から
日後である。ただし、今日が1週間のうち何日目なのかは分からない。
個の予定が全て休日になる可能性があるかを判定せよ。
制約
考察
この問題は、コンテスト終了時に自分を含め多くの人が 「WA が1個出てしまい解けなかった...」という事態に陥ったことと思う。そのため、 WAx1 が出てしまう解法とその原因、そして正しい解法について書くことにする。
誤解法
まず、簡単な例で考えてみよう。入力が
2 2 5 2 3
の場合について考える。「今日」が1週間のうち何日目なのかを考えると、予定の日の配置は全部で 通りある。
☆
を「今日」、o
を予定の日とすると、この例では以下の7通りの配置が考えられる。
これより、「今日」が1週間のうちの6日目であれば条件を満たすことになり、このケースの判定はYes
となる。
ここで、予定がある曜日 (1週間のうちの何日目にあるのか) に注目して考えるために、各 を
で割った余りを考えることにする。このケースなら、図は以下のようになる。
この図をじっと見ていると、判定すべき問題は次のように言い換えられることに気付く。
「☆
をずらしていって、赤の範囲に全てのo
を収めることができるか?」
つまり、
「左端のo
と右端のo
を同時に赤の範囲に収めることができるか?」
この問題を判定するプログラムをこんな感じに実装してみた。
#include <bits/stdc++.h> using namespace std; #define all(x) (x).begin(), (x).end() #define rep(i, start, end) for (ll i = (start); i < (ll)(end); i++) using ll = long long; // ======================================== // int main() { ll N, A, B; cin >> N >> A >> B; vector<ll> D(N); rep(i, 0, N) { cin >> D[i]; D[i] %= A + B; } sort(all(D)); if (D[D.size() - 1] - D[0] + 1 <= A) cout << "Yes" << endl; else cout << "No" << endl; }
D
に予定がある日の曜日を格納し、昇順にソート。その最大値と最小値の差+1が休日の区間 以下であればよい、としている。
これを提出すると、こんな結果になる。
![](https://cdn-ak.f.st-hatena.com/images/fotolife/Y/Yuulis/20240606/20240606185710.png)
orz
誤判定の原因と正しい解法
先ほどの解法、一見正しそうに思えるが、実はこんなコーナーケースで落ちる。
2 2 5 6 7
図示すると、こんな感じ。
☆
をずらしていけば確かに2つのo
が休日の範囲に収まるのだが、与えられた数値は6, 7
。これらを すると
となり、2つの予定の日数差は
となって
より大きくなるので、先ほどのプログラムではこのケースは
No
となってしまい、正しく判定されない。
では、どうすればよいのだろうか。実は一番最初の図がヒントになっている。
要件としては、上の例で言う を
としてあげたいので、
を取った後の各
D[i]
に を加えたものを
D
に追加して、 を求め、それが
以下であるかを判定しよう。
をずらしていく操作が、前述した
☆
を図らしていく操作に対応している。
なお、コードでは 0-indexed になっていることに注意。
コード
#include <bits/stdc++.h> using namespace std; #define all(x) (x).begin(), (x).end() #define rep(i, start, end) for (ll i = (start); i < (ll)(end); i++) using ll = long long; // ======================================== // int main() { ll N, A, B; cin >> N >> A >> B; vector<ll> D(N); rep(i, 0, N) { cin >> D[i]; D[i] %= A + B; } sort(all(D)); rep(i, 0, N) D.push_back(D[i] + A + B); ll diff = INF; rep(i, 0, N) diff = min(diff, D[i + N - 1] - D[i] + 1); if (diff <= A) cout << "Yes" << endl; else cout << "No" << endl;
実装時間: 50分
コンテスト中の WAx1 ほど嫌なことは無い。