Editorial for 第2回卬高杯 A問題 - Shizukou Days


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Author: RenCoda3

概略

  • この問題は、複数回の条件分岐(if文)によって解くことができます。
  • 最大14回のif文を書くことで解けますが、それより簡潔に書く方法もあるため、そちらもあわせて紹介します(下記参照)。

条件分岐の方法、主なパターン

なぜ工夫して書きたがるのか 競技プログラミングの世界では、基本的に1つの大会に数個の問題しか出ません。
部分点がある場合もありますが、そうでない問題は完答しなければ0点です。
同じ点数になると、「どちらがより速く問題を解き終えたか」の勝負になり、
これだけで順位が大きく変わってしまいます(特に簡単な問題が多いほど、その傾向は顕著に現れる)。
また、全ての問題には「時間制限」が存在し、決められた時間以内にプログラムが答えを出せなければ不正解(TLE=時間制限超過)になってしまいます。
簡潔に書くことで、時間制限内に収める事ができます。
これらが主な理由です。
※あとは入力ミスを減らすことができるなど。コードをできるだけ短く書きたがる変わった人たちプログラマーや大会もあり、それも1つの理由。

1. それぞれの日ごと対応させてしまう

実装例1(C++20):


#include <bits/stdc++.h>
using namespace std;

int main(){
    string s;
    string t;
    cin >> s >> t;
    if(t=="A"){
        if(s=="Sunday"){
            cout << "No" << endl;
        }
        else if(s=="Monday"){
            cout << "Yes" << endl;
        }
        else if(s=="Tuesday"){
            cout << "Yes" << endl;
        }
        else if(s=="Wednesday"){
            cout << "Yes" << endl;
        }
        else if(s=="Thursday"){
            cout << "Yes" << endl;
        }
        else if(s=="Friday"){
            cout << "Yes" << endl;
        }
        else if(s=="Saturday"){
            cout << "Yes" << endl;
        }
    }
    else if(t=="B"){
        if(s=="Sunday"){
            cout << "No" << endl;
        }
        else if(s=="Monday"){
            cout << "Yes" << endl;
        }
        else if(s=="Tuesday"){
            cout << "Yes" << endl;
        }
        else if(s=="Wednesday"){
            cout << "Yes" << endl;
        }
        else if(s=="Thursday"){
            cout << "Yes" << endl;
        }
        else if(s=="Friday"){
            cout << "Yes" << endl;
        }
        else if(s=="Saturday"){
            cout << "No" << endl;
        }
    }
}
すごく…(コード長が)大きいです… これでは書き終えるまでに時間がかかってしまいます。1秒を争う中でこんなコードを書いていられません。 何かもっといい方法はないでしょうか。

2. あるものに注目する

ここまでで、何か感じたことはありませんか?

…そうです。Noです。

Noとなる日は日曜日とB週日課の土曜日だけ。

他は全部Yesになるのだから、この3日に注目して条件分岐をしてみましょう。

実装例2(C++20):


#include <bits/stdc++.h>
using namespace std;

int main(){
    string s;
    string t;
    cin >> s >> t;
    if(s=="Sunday"){
        cout << "No" << endl;
    }
    else if(s=="Saturday"){
        if(t=="B"){
            cout << "No" << endl;
        }
        else{
            cout << "Yes" << endl;
        }
    }
    else{
        cout << "Yes" << endl;
    }
}
これをノーヒントで書けたならば、あなたは競技プログラミングにかなり向いていると思います。きっと。
最後に、もう少しだけ短くしてみましょう。

3. さらに短く書く方法

  • 変数の宣言において、同じ型(文字列が入るのか、数値が入るのかを決める定義的なもの)であれば、,を使って複数の変数を宣言できてしまいます。
  • &&||を用いて、複数の条件式を1つにまとめていきます。例えば、if(A&&B){(実行)}if(C||D){(実行)}というコードを書いた時、それぞれ「AかつB ならば(実行)」「CまたはD ならば(実行)」という意味になります。
  • if文は、その中の実行内容が1つだけ(セミコロン1つだけ)の場合は、{}を省略して書く事ができてしまいます。
実装例3(C++20):


#include <bits/stdc++.h>
using namespace std;

int main(){
    string s, t;
    cin >> s >> t;
    if((s=="Sunday") || (s=="Saturday" && t=="B")) cout << "No";
    else cout << "Yes";
}
最終的にコードを10行以内で書き終える事ができたので、私の解説はここで終わりにしようと思います。

補足

  • 実際には、B週日課にもかかわらず土曜日も授業があったり、A週日課なのに土曜日に授業がなかったりします。予定はしっかり確認しておきましょう。

Comments

There are no comments at the moment.