CodeIQ 三角形は何通り?
今日は以下の問題を解いてみました。
――――――――――――――――――――――――――――――――――――――――――
【問題】
入力nに対して
(はすべて整数)を満たすの中で、
これらを3辺とする三角形が成り立つ場合の組み合わせを求めるプログラムを書いてください。
【入力】
標準入力から、整数が与えられます。
【出力】
標準出力に、条件を満たす組み合わせの総数のみを出力してください。
――――――――――――――――――――――――――――――――――――――――――
まずは何も考えずにとなる組み合わせを全て調べてみます。
//CodeIQ 三角形は何通り?:愚直に全探索 #include<iostream> using namespace std; int64_t solve(const int n) { int64_t count = 0; for (int c = n;c >= 1;c--) { for (int b = c;b >= 1;b--) { for (int a = b;a >= 1;a--) { if (a + b > c) { count++; } } } } return count; } int main() { int n; cin >> n; cout << solve(n) << endl; return 0; }
とりあえず1回提出してみたところ
「時間かかりすぎや、出直してこいm9(^Д^)プギャー」と弾かれました。
それもそのはずで、計算量はとなってしまい
n=1,000,000の場合、到底1秒以内で答えを出せそうもありません。
もっと良いアルゴリズムを考えないといけないわけです。
まずはc=nの場合で全部の組み合わせを樹形図にしてみます。
となる組み合わせは、
のとき、の通り
のとき、の通り
のとき、の通り
※ただし、(は切り捨て)ならば、
・cが奇数ならばの通り
・cが偶数ならばの通り
の総和(ただしの場合のみ)となります。
この総和をと置くことにします。
のとき、 より
のとき、 より
のとき、より
のとき、より
…
となります。カッコ内の分数は全て切り捨てです。
これを並べてみると
となり、漸化式で表すことができます。
よって、一般項は
と表すことができます。
これをからまでの総和を求めればよいので、
三角形は通りとなります。
後はこれをプログラムで実装すればいいのです。
※solve関数以外の場所は書き換えておりません。
int64_t solve(const int n) { int64_t count = 0; int64_t sum_o = 0, sum_e = 0; for (int i = 1;i <= n;i++) { if ((i & 1) == 0) { sum_o += i; count += sum_o; } else { sum_e += i; count += sum_e; } } return count; }