メチャメチャだけど【随時更新】解答に必要な機能まとめ - ニート歴10年からの数学日記と【随時更新】計算量の減らし方まとめ - ニート歴10年からの数学日記を使って、算数オリンピックについて考察していく。
グラフや幾何学の問題や、記述に関するメタ的な問題以外の今までに無い種類の問題について考察する。
『3人の生徒に算数のテストが返されました。3人はみなことなる点数で、0点の人や100点満点をとった人はいません。3人はそれぞれ自分が3人の中で何番目に高い点数を取っているかは先生に教えてもらいましたが、他の2人が何点をとったかということや、何番目に点数が高いかということはわかりません。そこで、おたがいにヒントを出し合いました。
岡部くん「ぼくの点数は10の倍数でした」
田中くん「ぼくの点数は12の倍数だった」
森内さん「わたしの点数は14の倍数だったわ」
このとき、田中くんが次のように言いました。
田中くん「今のでみんなの点数がわかったよ」
田中くんの点数は何点でしたか。』
Okabe ≠ Tanaka ≠ Moriuchi ≠ 0 ≠ 100;
[A, B, C] := カブり無し:カブり無し := [Okabe, Tanaka, Moriuchi];
A < B < C;
Okabe == 10 * ?;
Tanaka == 12 * ?;
Moriuchi == 14 * ?;
({Tanaka == (A, B, C).1}, Tanaka)を結果が1通りに定まるように設定; ??今回はこれで良いけど、ABCという名前自体にアクセスできるかというのが問題、中身の数値になってしまうと結果として参照できないかもしれない
結果におけるTanaka;
岡部は10,20,30,40,50,60,70,80,90。Tanakaは12,24,36,48,60,72,84,96。Moriuchiは14,28,42,56,70,84,98。
一番制約が大きい端っこから見ていくと、Tanakaが84の時に3番目だと、同着は無いのでOkabeは90、Moriuchiは98に定まるのではないか。
それぞれの視点の設定という機能があっても良いかもしれない。必要になれば作る。機能としては必要無いかもしれないけど、何か本質的な気がする。
『4クラス対抗のリレーが行われました。各チーム、5人の走者が走ります。次のAクラスの5人のレース後のコメントを読んで問題に答えなさい。
高橋「結局準優勝だった。」
三輪「ぼくは、2クラス抜いたのですけど、最後に他のもう1クラスに抜かれました。」
中島「ぼくは三輪君からバトンをもらって走りました。」
斎藤「ぼくがバトンを落としたせいで1位からビリになっちゃった。」
高野「アンカー(5走)の人が順位を上げてくれました。」
回答らんに走った人の名前と、バトンをわたした(またはゴールした)ときのAクラスの順位を書きなさい。』
記述する方法が分からない。保留。
『3けたの整数のうち、次の条件を満たすものを「良い整数」とよぶことにします。
条件:3けたの整数を2つの整数に分けてその和を考えると、常にもとの整数の約数になっている。
(例)330は3と30に分けても、33と0に分けても和が330の約数になっています。このため、330は「良い整数」となります。ですが、702は7と02に分けた場合は約数になりますが、70と2に分けてしまうと約数になりません。よって、702は「良い整数」ではありません。
一の位が0でない「良い整数」を4個求めなさい。』
100*A + 10*B + C == (10*A + B + C) * ?;
100*A + 10*B + C == (A + 10*B + C) * ?;
結果における(100*A + 10*B + C);
(A+C)*? == 10*? + Cでなければならない。A*X + C*(X-1) == 10*?。例えばAが5、Cが2、Xが6だと、一応成立。
Cは4・6・8でもあり得るか。
100*5 + 10*B + 2 == (5 + 10*B + 2) * 6、10*B - 502 == 30 + 60*B + 12、-544 == 50*B。駄目だ。
100*5 + 10*B + 4 == (5 + 10*B + 4) * 6、10*B - 504 == 30 + 60*B + 24、-558 == 50*B。6だと-572、8だと-586。やっぱり駄目。
100*A + 10*B + C == (10*A + B + C) * ?で、Bが5、Cが2、?が6でも良いので、それでも試してみる。
100*A + 10*5 + 2 == (10*A + 5 + 2) * 6、100*A + 52 == 60*A + 30 + 12、40*A == -10。
100*A + 10*5 + 4 == (10*A + 5 + 4) * 6、100*A + 54 == 60*A + 30 + 24、40*A == 0。Aが0は無いだろうから駄目。
観察すると以下10ずつ増えていくから、6だと10、8だと20。やはり駄目。
Aが1、Cが8、Xが2はどうだろう。AとCが合わせて9で、Xが(A+1)なら、最後に余ったAで、今までの9を埋めていく感じで。
100*1 + 10*B + 8 == (1 + 10*B + 8)*2、10*B + 108 == 20*B + 18、90 == 10*B、B == 9。198。しかし上の条件が成立しない。
Cが(9-A)、Xが(A+1)で、上の式に代入してみれば良いのかな?
100*A + 10*B + (9-A) == (10*A + B + 9-A) * (A+1)。ああ、面倒くさいな。9通りならやるべきかな。
答えを見ると、ある数の倍数から、ある数の倍数を引くと、ある数の倍数になることを利用する。
つまり(100*A + 10*B + C)が(10*A + B + C)の倍数なら、(10*A + B + C)*10 - (100*A + 10*B + C) == 9*Cは (10*A + B + C)の倍数。…①
(100*A + 10*B + C)が(A + 10*B + C)の倍数なら、(100*A + 10*B + C) - (A + 10*B + C) == 99*Aは(A + 10*B + C)の倍数。…②
Cで場合分けする。
Cが1だと、①より、9は10*A + B + Cの倍数になる。しかしAは整数なのでこれは無理。
Cが2だと、〜。
で、以下、①の条件で出てきた数字を、②に当てはめて確かめる。
倍数の利用による単純化で、確かにスマートだなと思った。
『下の図のような2つのツマミがあり、どちらも0から5までの目盛りがついています。いま、ツマミはどちらも0の目盛りを指しています。大小2つのサイコロを同時にふって出た目によって、次のような手順でツマミを回します。
手順
1.右のツマミの指している数字と同じ数だけ左のツマミを反時計回りに回す。
2.大きなサイコロの目の数字と同じだけ、左のツマミを時計回りに回す。
3.左のツマミを指している数字と同じ数だけ右のツマミを反時計回りに回す。
4.小さなサイコロの目の数字と同じだけ、右のツマミを時計回りに回す。
たとえば、1回目にサイコロをふって大きなサイコロの目が4、小さなサイコロの目が3の場合、
1.では左のツマミが0を指しているので何も変化せず、
2.で左のツマミを時計回りに4つ回すので左のツマミは4を指し、
3.で右のツマミを反時計回りに4つ回すので右のツマミは2を指し、
4.で右のツマミを時計回りに3つ回すので右のツマミは5を指します。
大小のサイコロを3回ふってツマミを回し終えたとき、ツマミがどちらも0を指しているような目の出方は何通りありますか。
(図では、反時計回りに数字が進んでいっている)』
right_control := 循環リストで[0, 1, 2, 3, 4, 5];
left_control := 循環リストで[0, 1, 2, 3, 4, 5];
right_point := 0;
left_point := 0;
big_dice_list := ;
small_dice_list := ;
for(i := 0; i < 3; i++){
big_dice := [1, 2, 3, 4, 5, 6].1;
small_dice := [1, 2, 3, 4, 5, 6].1;
big_dice_list := 末尾に新しく挿入 := big_dice;
small_dice_list := 末尾に新しく挿入 := small_dice;
left_point := left_point + right_control[right_point];
left_point := left_point - big_dice;
right_point := right_point + left_control[left_point];
right_point := right_point - small_dice;
}
right_control[right_point] == 0;
left_control[left_point] == 0;
結果における(big_dice_list, small_dice_list).数;
サイコロでのマイナスと、もう一方のツマミでのプラスが、全部足して6の倍数になる場合を考えれば良い。
最高が12。最低が-18。それぞれを並列で考えて、後から順番違いの分を計算すれば良い。
12を出すツマミは、(5,5,5),(5,5,4),(5,5,3),(5,5,2),(5,4,4),(5,4,3),(4,4,4)の場合が考えられる。
いやしかし、サイコロには0は無いので、あり得るのはツマミの(5,5,5)に対してサイコロの(1,1,1)の場合だけか。
6を出すツマミは、つまり9以上を出すツマミ全てなので……。いや流石に違う方法があるのではないか。
目の出方の種類だけを考えれば良いのであれば……。いや分からないな。
1回目に左のツマミを回さないことを利用するのかな?そうすると、プラス方向には最大で1回、マイナス方向には最大で3回だが。
プラス方向に1回の場合は、右のツマミが(5,5),(5,4)。(5,5)の場合のサイコロは(2,1,1)。(5,4)の場合のサイコロは(1,1,1)。
プラス方向に0回の場合は、右のツマミが(5,5)~(4,0),(3,3),(3,2),(3,1),(3,0),(2,1)。いややっぱり面倒だな。どうするんだろう。
答えを見ると、最初の2回のサイコロの出目がどのようであっても、それをそれぞれ0に戻せる出目が必ず1通りずつある。よって36*36=1296通りが答え。これはどう考えれば良かったんだろう。18.4%が正解している。
『A〜H君の8人が100m競争を8回しました。
Aは8回のうち7回Bに勝ちました。
Bは8回のうち7回Cに勝ちました。
Cは8回のうち7回Dに勝ちました。
Dは8回のうち7回Eに勝ちました。
Eは8回のうち7回Fに勝ちました。
Fは8回のうち7回Gに勝ちました。
Gは8回のうち7回Hに勝ちました。
Hは8回のうち7回Aに勝ちました。
Bが8位だったときの1位はだれでしょうか。ただし、どの回も同着(2人以上が同じ順位になること)はありませんでした。』
rank := [~7][~7]のリスト;
for(i := 0; i < 8; i++){
rank[i][,,,,,,,] := 全部:カブり無し := [A, B, C, D, E, F, G, H];
}
rank[?].@(A < B).数 == 7;
rank[?].@(B < C).数 == 7;
rank[?].@(C < D).数 == 7;
rank[?].@(D < E).数 == 7;
rank[?].@(E < F).数 == 7;
rank[?].@(F < G).数 == 7;
rank[?].@(G < H).数 == 7;
rank[?].@(H < A).数 == 7;
結果におけるrank[?].[?1: ?1[7] == B][0];
ランダムで無く、どれも対称な配置を考えると、毎回一個ずつズレた場合が考えられる。Bが8位の時の1位はC。軽くする方法という区分でこれがどういうことなのかは分からない。
『下図のような5×5のマス目に6個の○を次の条件を満たすように書きます。
条件:各行・各列に少なくとも1個は○を書く、同じマスには2個以上の○を書くことはできない。
このとき、6個の○を書く方法は全部で何通りありますか。
(図は省略)』
table := [~4][~4]のリスト;
table[?][?] := カブり無し:6 := "○";
table[0][?] ∋ "○"; ??もっと効率の良い指定方法が欲しい
table[1][?] ∋ "○";
table[2][?] ∋ "○";
table[3][?] ∋ "○";
table[4][?] ∋ "○";
table[?][0] ∋ "○";
table[?][1] ∋ "○";
table[?][2] ∋ "○";
table[?][3] ∋ "○";
table[?][4] ∋ "○";
結果における数;
まあ普通に、端っこの列から、一個ずつ行が被らないように置いていく場合の数を考えてみる。5*4*3*2=120通り。
その後に、20マスに1個置くわけだから、120*20=2400通り。
問題は、置いた後にパターンが被るかだが、被らないんじゃないかと思う。だから2400通りが答えではないか。
答えを見ると、○が2個ある行と2個ある列ができるわけだが、俺が考えた場合は、その行と列が被っていて、一つの○になっている場合でしか無いらしい。
被らないパターンだと、まず列と行を選んでそれぞれ5通り、その列と行でもう一方の行や列と被らないように2つ選ぶ。消去法で残る最後の4マスで2通り。
ただ、解答だと、なぜかもう一方の行や列に被らないで選ぶ際に、3*2で6通りという説明になっている。普通に考えたら4*3で12通りだと思うんだが。解答だと、後者は1800通り、だが普通に考えたら、後者は7200通りではないか。
ちなみに、被るパターンだと、まず行と列を選んで、被った所以外から4通りで選んで、最後の3マスで3×2×1で6通り。5*5*4*4*6=2400通りという説明だった。