プログラミングのお題スレ Part22
しらみ潰しとは例えば1から順番に見つかるまで全てを試していく最悪な方法を指す
今回の場合だと与えた数から順番に見つかるまで±1を続けて全てを試していって探すプログラムが該当する
>>262 私は
>>248 だけれども、解法としてはそれしかないと思いますね
>>249 と
>>238 は
しらみ潰しではなく
きちんとプログラミングして算出しているようにみえますね
>>264 私は解答は提出していないが、ざっくりと自分が思いついた方法
まず、以下のような操作を考える
A. 1234という入力に対して1234321を返す
B. 1234という入力に対して12344321を返す
ここで、xという入力に対してA,Bが返す数をA(x),B(x)と表すことにする
次に、与えられた数の桁数で場合分け
(1)与えられた数字の桁数が奇数の場合
例として5桁の数字を考える
N=a*10000+b*1000+c*100+d*10+e*1 (a~eは1桁の自然数, aは0でない)
が与えられたとき、
M=a*100+b*10+c*1
とすると、N=10000の場合を除いて、Nに最も近い回文数は
A(M), A(M+1), A(M-1)
の3つの候補に絞られる(厳密にはA(M)とNとの大小比較からA(M±1)の何れかは明らかに候補にならないので2つを考えれば良い)
N=10000の場合は9999と10001が答え
(2)与えられた数の桁数が偶数の場合
例として6桁の数を考える
(1)と同様に
N=a*100000+b*10000+c*1000+d*100+e*10+f*1
に対して
M=a*100+b*10+c*1
とすると、N=100000の場合を除いて
B(M), B(M+1), B(M-1)
のどれかがNに最も近い回文数(厳密には以下略)
N=100000の場合は99999と100001が答え
十分大きな数に対しては虱潰しに回文判定していくより速く求まる
>>259 Iterable.generate(n).map(f)は単に
Iterable.generate(n, f)で良かったと判明
>>234 >>249をC++で書き換え(入力値は64ビット整数の範囲内限定)
https://ideone.com/e1AM8A 元々はCで書き、4行目はなし、15行目と24行目はstrrev(s + i);だったが、Windowsのgccでは
コンパイルできたのにideoneではできなかったので、仕方なくC++にしてstd::reverseで代用した。
>>234
Rust
fn nearest_palindrome_numbers(n: usize) -> Vec<usize> {
let mut dd = DecimalDigits::new(n);
dd.palindrome_using_upper_half();
let n1 = dd.to_number();
match compare(n, n1) {
Equal => return vec![n],
Greater => dd.increment_upper_half(),
Less => dd.decrement_upper_half(),
}
if dd.is_most_upper_zero() {
return vec![n - 1, n + 1];
}
dd.palindrome_using_upper_half();
let n2 = dd.to_number();
match compare_absolute_diff((n, n1), (n, n2)) {
Less => return vec![n1],
Greater => return vec![n2],
Equal => return if n1 < n2 { vec![n1, n2] } else { vec![n2, n1] },
}
} >>267 N=17=1*10+7*1のとき、Nは2桁(偶数桁)でM=1*1=1
B(M)=B(1)=11はNより小さいのでB(M-1)は考えなくてよい
B(M+1)=B(2)=22なので11,22が答えの候補
11より22のほうが17に近いので22が答え
ちょっとNに対するMの説明が足りてなかったけど言葉で上手く言い表せないすみません(上位半分以上かつ最小の桁数を抜き出す、的な)
>>234 >>269の一部でC++の機能をどうせ使ってしまったので、この際、全部をC++流に変えたら
C流よりすっきり書けた。
https://ideone.com/38bo2E >>273 > [1000, [1001]]
誤:ps = [p.(s), p.(t.to_i.pred.abs.to_s + u), p.(t.succ + u)]
正:ps = [p.(s), p.(t.to_i.pred.abs.to_s + u), p.(t.succ + u), p.(s.to_i.pred.abs.to_s)]
とりあえず雑に修正してみたが?
(ノ∀`)アチャー
>>262 >>245のKotlinのプログラムは何も考えてなくて本当に馬鹿正直に±1して一つ一つ検査する方式で作ったんだけど、それでもあなたのテストではダメということになったの?
まあ Int (符号付32bit整数) 使ってるからその限界超えたらダメではあるんだけど、そういう問題ではなく?
>>276 それはしらみつぶしと言われる駄目プログラミングだよ
例えば求める解法が存在する方程式を解くのに値を±1しながら順に代入して試していくのと同じ
>>277 あー。プログラムにバグがあってまともに答えが出ないっていうことではなく何の捻りもないプログラムだからダメっていう感想ね。それならわかる。
こちらもアルゴリズム思い浮かばないけどとりあえず作ってみただけだし。ダメというほどではないが良いとも思えないプログラムなので。
>>234 ruby
https://ideone.com/E9VSE3 ・273の[1000, [1001]]バグ修正版
・275とは違う方法で修正してみたがやっつけ感大
>>234 ruby 2.5.5
https://ideone.com/1zqSr1 ・いわゆる(?)ジェネレータ版
・「終端を持たない範囲オブジェクト」はRuby 2.6.0から
>>234 ruby 2.5.5
https://ideone.com/04fxGM ・ジェネレータ版ちょっとアレンジ
・to_sしてto_iするのをやめた
異なる自然数 a, b (a > b) における a^3 - b^3 を「a, b の三乗差」と呼ぶことにする。
異なる5通りの組(a, b) (c, d) ... (j, k) について三乗差がすべて相等しいとき
その組(a, b)...(j, k) および三乗差自体を求めよ
異なる6通りの組で三乗差が相等しい場合があるかも検討せよ
>>282 [(1134, 357), (1155, 504), (1246, 805), (2115, 2004), (4746, 4725)]
a^3 - b^3 == 1412774811
>>282 aが5000以下限定で
>>283の解はRで5秒以内に求められた。8〜9行目は下三角行列の要素番号から
行番号と列番号を求めているだけで、
>>282を解く特別なアルゴリズムというわけではない。
https://ideone.com/w4X3DC >>282 ruby 2.5.5
https://ideone.com/4GdMaO ・285の無駄なループ回数を削減
・でも5秒じゃ_
>>282 >>287は下三角行列の要素番号から列番号を求めるのに2次方程式を解くのが分かりにくかったから、
各列の最下行の要素番号を計算しておいてそれを二分探索するように変更した。
https://ideone.com/Tefgkh n = 25000で実行してみても、n = 5000ときの解のa, bを両方とも2, 3, 4, 5倍した解しか別に
見つからなかった。
>>282 >>289と似た手順でC++
https://ideone.com/nFRsrK Rではソートする前に重複値だけを抽出しているが、C++のunique関数はソート済みデータにしか
使えないので使っていない。
>>282 下三角行列の各列内の要素は昇順で既に並んでいるのに、
>>290は下三角行列の全要素を
ソートして無駄なので、列のマージに変更(要するにマージソートを途中段階から開始)
したら少し速くなった。
https://ideone.com/EZSvB3 n = 10000でも5秒以内に終わった。
https://ideone.com/huQiBe >>282 >>292とは別の方法で
>>290を高速化
https://ideone.com/QxjmyT 1³, 2³, 3³, …, 5000³をD = 5001で割った余りはすべて異なる値になるから、d = a³ − b³を
Dで割った余りはどれか1つの値に偏ることなく均等に分布する。dをDで割った余りによりdを
区分すれば、各区分に入る個数はどれも多すぎないのでソートに時間が余りかからない。
Dの値はconstexpr関数によりコンパイラに計算させている。n = 10000, 15000のときは
それぞれD = 10002, 15009になる。
>>282 c
https://ideone.com/JnJpJW ・291から省メモリ化
旧:unsigned int values[10];
新:unsinged short values[4];
>>282 C++
https://ideone.com/1c4s5I >>294はa, bの二重ループ内でa³ − b³をD = 5001で割った余りrにより区分していたが、
rのループ内でa, bを変化させるように変更したら、2次元配列がなくなってすっきりした。
その結果、メモリ使用量が激減し、nが大きい場合でも実行できるようになった。
>>296の続き
n = 1000000, m = 6で実行すると、12通りの解が見つかった。
[6つ組解]
424910390480793: (75978, 23919), (77385, 33768), (83482, 53935), (141705, 134268), (317982, 316575), (596001, 595602)
620174235433536: (86184, 27132), (87780, 38304), (90237, 48573), (94696, 61180), (160740, 152304), (360696, 359100)
1238805803151000: (107487, 14487), (108540, 34170), (110550, 48240), (119260, 77050), (454260, 452250), (851430, 850860)
1384074844012224: (112152, 29844), (125324, 83600), (130050, 93426), (159372, 138624), (224928, 215412), (357447, 353799)
1936290882196125: (127629, 52254), (133320, 75675), (149285, 111620), (228525, 215430), (246510, 235395), (290214, 282339)
4589726535576000: (170172, 69672), (177760, 100900), (185265, 120945), (304700, 287240), (328680, 313860), (386952, 376452)
4961393883468288: (172368, 54264), (175560, 76608), (180474, 97146), (189392, 122360), (321480, 304608), (721392, 718200)
11072598752097792: (224304, 59688), (250648, 167200), (260100, 186852), (318744, 277248), (449856, 430824), (714894, 707598)
36717812284608000: (340344, 139344), (355520, 201800), (370530, 241890), (609400, 574480), (657360, 627720), (773904, 752904)
52279853819295375: (382887, 156762), (399960, 227025), (447855, 334860), (685575, 646290), (739530, 706185), (870642, 847017)
[7つ組解]
15490327057569000: (249281, 6281), (255258, 104508), (266640, 151350), (298570, 223240), (457050, 430860), (493020, 470790), (580428, 564678)
123922616460552000: (498562, 12562), (510516, 209016), (533280, 302700), (555795, 362835), (597140, 446480), (914100, 861720), (986040, 941580)
6つ組解の(2, 7), (4, 8), (5, 10), (6, 9)番目は各括弧内で自然数比になっている。
6つ組解の5番目の2倍は7つ組解の1番目のうちの6組を構成している。
>>282 C++
https://ideone.com/tM1cuo >>296のrのループ内でa³ − b³をD2 = 5003で割った余りr2により区分し、それぞれの区分ごとに
解を探すようにしたら速くなった。ただし、nが大きい場合にはかえって遅くなる。
>>297 出題者です。
すごいです。ありがとうございます。私の手元ではまだ6通り解、7通り解のひとつも入手できていないので、参考になりました
私のアルゴリズムは効率が悪いようですね
>>282 C++
https://ideone.com/LEU7EV >>298でnを大きくするにつれ
>>296に対する高速化効果が薄れていくのは、ABをvectorでなく
配列にしたらある程度改善された。n = 5000のときの実行時間は
>>296の半分以下になった。
ただし、n = 1000000まで大きくすると、296よりやっぱり遅くなる。
>>299 どんなプログラムを書いたのか見せて。
>>282 C++
https://ideone.com/PG6UiY >>300の実行時間を分析すると、最も時間が掛かっているのは46〜と47行目だと判明した。
そこで配列ABの第1次元と第2次元を入れ替えてみると、n = 5000では変わらないが、
1万, 2万, 5万, 10万, 20万では35%前後高速になった。これは、改良前には第2次元の添字が
小さい要素に書き込みが集中しているため、改良後のように第1次元に入れ替えた方が
纏まったメモリ領域に書き込みが集中しキャッシュの効きが良くなるからだと考えられる。
一方、n = 100万で高速化しないのは、書き込み集中領域が大きすぎるからだろう。
https://ideone.com/6RzW0n n = 100万の場合にはr2の値によってデータを多数の列へ振り分けるのをやめ、列を1つにして、
その内部でr2の値により2種類に区分し、それぞれの内部で2種類にさらに区分し、…と再帰的に
区分していけば(要するにクイックソートの変形版)、1つの配列内での要素のスワップだけで済み、
キャッシュの効きが改善されるとの予想通り、n = 100万で実行速度は
>>296より25%速くなった。
(原理的には
>>300より非効率なのでn = 5000では
>>300より当然遅い)
>>301 ハズレが多いから2passは効果ある?
>>282 C++
https://ideone.com/xQD1W8 関数mainのループで配列A, B, Pに書き込まずdにだけ書き込むようにし、関数FindDuplicatesで
dの添字Pではなくdそのものをソートするように変えて、n = 1000000の場合に
>>301より10%高速化。
関数PrintSolutionでa, bをmainでと同じ方法で再計算するのは非効率だが、PrintSolutionは僅か12回しか
呼ばれないため、全体の実行時間への影響は無視できる。
お題
460円 580円 600円 の3種類の商品があります
これらを組み合わせて合計10個買ったら5360円になりました
組み合わせを求めるプログラムを書いてください
ちなみに答えの一つは
・600円×2
・580円×4
・460円×4
だそうです
https://rio2016.5ch.net/test/read.cgi/cigaret/1706726196/56-57 >>304 面倒なので全て460円を引くと
A=0円 B=120円 C=140円
10個で760円という問題
面倒なのでさらに20で割ると
A=0円 B=6 C=7円
10個で38円という問題
つまり唯一奇数のCは偶数個が確定
Cが6個以上だと42円以上でオーバーしてNG
Cが4個だと28円で残り10円をA,Bで作れないからNG
Cが2個だと14円で残り24円はBが4個で残り4個がA
Cが0個だと0円で残り38円をA,Bで作れないからNG
つまり解は(A,B,C)=(4,4,2)しかない
>>304 Rで全探索でなくちゃんと解くと
https://ideone.com/F44pCL 解が複数ある場合と全くない場合の例として、600円を540円と520円に変更したときの出力も載せた。
2pass案は多少工夫したらかなり速い
n ␣␣m ␣296␣ ␣301-1 ␣301-2 ␣303␣ ␣2pass
5k␣␣5 ␣ 0.5s ␣ 0.1s ␣ 0.5s ␣ 0.4s ␣ 0.1s
25k ␣5 ␣12.7s ␣ 2.5s ␣13.9s ␣11.1s ␣ 1.7s
100k␣5 ␣3m52s ␣49.3s ␣4m13s ␣3m26s ␣38.9s
1M* ␣6 ␣8h23m ␣2h50m ␣8h51m ␣6h43m ␣1h11m
*n=100万は1万サンプルの部分ループ500k≦r<510kから100倍
>>301の296と301-2の比較記述と違う傾向があるのはキャッシュ階層の違いだと思う
2passは301-1に近いけど1pass目でのランダムアクセスサイズを落としながらも
誤判定率を低く抑える(0.2%~2%)工夫をするのがお楽しみだと思う
>>304 a = (600, 580, 460)
m = min(a)
h = set()
def buy(b, yen):
if yen < m: return
for i in range(0, len(a)):
v = a[i]
if yen >= v:
b[i] += 1
if yen == v:
h.add(str(b))
else:
buy(b, yen - v)
b[i] -= 1
buy([0, 0, 0], 5360)
for s in h: print(s)
>>304 Haskell
[(a, b, c) | a <- [0..20], b <- [0..20], c <- [0..20], a * 460 + b * 580 + c * 600 == 5360]
output: [(0,2,7),(4,4,2)]
合計10個という条件忘れてた。
[(a, b, c) | a <- [0..20], b <- [0..20], c <- [0..20], a + b + c == 10, a * 460 + b * 580 + c * 600 == 5360]
output: [(4,4,2)]
大幅に手直しした
特に前回数値が一部出てこない状態になっていたので色々と手動で最適化した
新しいアイディアを思いつかない限りはシングルスレッドでの限界に近いと思う
n m 301-1 303 2pass 2pass'
5k 5 0.1s 0.4s 0.1s 0.1s
25k 5 2.5s 11.1s 2.3s* 1.7s
100k 5 49.3s 3m26s 38.9s 27.7s
1M* 6 2h50m 6h43m 1h11m 48m10s
2M* 6 17h06m 28h27m 5h47m 3h13m
Max* 6 35h51m 51h23m 11h09m 5h47m
*前回
>>309 2pass n=25kの再計測値
*n=1Mは部分ループ500k<=r<510kから100倍
*n=2Mは部分ループ500k<=r<505kから400倍
*Max:=2642245は3乗がUINT64に収まる最大
*n=Maxは部分ループ500k<=r<500k+3785から2642245/3785倍
ヒント含みの数値がこちら
n D1 D2 D3 = 5000 5001 5003 5009
false_positive = 23 / 5001 = 0.46%
total_t_pass1 = 64.220 ms 2.568 ns/iter
total_t_pass2 = 0.044 ms 0.381 ns/iter
real 0m0.097s
n D1 D2 D3 = 25000 25003 25005 25006
false_positive = 171 / 25003 = 0.68%
total_t_pass1 = 1654.681 ms 2.647 ns/iter
total_t_pass2 = 1.407 ms 0.329 ns/iter
real 0m1.709s
false_positive = 2211 / 100005 = 2.21%
total_t_pass1 = 27338.298 ms 2.734 ns/iter
total_t_pass2 = 78.402 ms 0.355 ns/iter
real 0m27.692s
n D1 D2 D3 = 1000000 1000002 1000009 1000015
false_positive = 18 / 10000 = 0.18%
total_t_pass1 = 28674.338 ms 2.867 ns/iter
total_t_pass2 = 5.642 ms 0.313 ns/iter
real 0m28.897s
n D1 D2 D3 = 2000000 2000003 2000013 2000015
false_positive = 13 / 5000 = 0.26%
total_t_pass1 = 28777.424 ms 2.878 ns/iter
total_t_pass2 = 8.620 ms 0.332 ns/iter
real 0m29.015s
n D1 D2 D3 = 2642245 2642246 2642253 2642258
false_positive = 315 / 3785 = 8.32%
total_t_pass1 = 29210.857 ms 2.921 ns/iter
total_t_pass2 = 336.864 ms 0.405 ns/iter
real 0m29.800s
>>304 ぶっちゃけ、他の言語の人と同じっぽくないので心配なんだが…。
自分なりにHaskellで全探索じゃないバージョン書いてみた。
Haskell
[(a, b, c) | a <- [0..10], b <- [0..10 - a], c <- [0..10 - (a + b)], a * 460 + b * 580 + c * 600 == 5360, a + b + c == 10]
答えは同じ[(4,4,2)]。
少し一般化して、N個の商品があり、i番目の商品はA_i円です
合計M個購入し、価格の合計がS円であるような購入の仕方を998244353で割った余りを求めてください
だとO(N M S)より小さい計算量で解けるのかな
2個、4個、8個…みたいにメモ化すればMはlogMにできるかもしれんね
空間がlogM倍されそうだが
>>319 https://ideone.com/YCi6qe ヘロンが作ったもう1つの式である平方根を加算と除算の繰り返しで求める式も使用。
sqrt関数を呼び出すより実行形式ファイルサイズがほんの少しだけ小さくなる。
>>321 無限ループにならない?
機械イプシロン(DBL_EPSILON)とか気になる
解答例
#include <stdio.h>
#include <math.h>
void heron(double, double, double);
int main(void)
{
double a, b, c;
printf("3辺a, b, cを入力せよ ");
scanf("%lf,%lf,%lf", &a, &b, &c);
heron(a, b, c);
}
void heron(double x, double y, double z) // heronの定義
{
double s, t;
s = (x+y+z)*0.5;
t = s*(s-x)*(s-y)*(s-z);
printf("3角形の面積は S=%g\n", sqrt(t));
return;
}
>>322 p < 0 のとき(= 三角形を作れない場合)は浮動小数点数の特性に関係なく無限ループになる。
sqrt(p) と同様にNANを返すには、if (p < 0) return 0 / (p - p); を追加すれば良い。
p > 0 のときは無限ループにならないはず。以下が検証プログラム。
https://ideone.com/mzemEM x = sqrt(p), y = p / x とすると、浮動小数点数の特性により x == y とならない場合は存在する。
このとき、xとyの仮数部を整数と見なした値(以降では「仮数整数」と呼ぶ)の差は1なので、
z = (x + y) / 2 はxとyのうち仮数整数が偶数の方に一致する。zを新たなxとして代入しyとzを
再計算すれば、今度はxの仮数整数が偶数なのでzはxに必ず一致し、
>>321の収束判定条件が成立する。
具体例で見ると、p = 2 のときはxの仮数整数が奇数なので x != z となるが、zを新たなxとして代入し
再計算すれば x == z が成立する。桁上がりが起こる p = 3.9999999999999996 のときも、同様に
再計算で x == z が成立する。p = 3 のときはxの仮数整数が偶数なので x == z が成立し再計算は不要。
>>325 解説ありがとう
俺には理解できないレベルだと分かりましたw
俺なら収束の自信が無くてDBL_EPSILONを使った判定と
ループ回数上限を組み合わせて実装しそうだ
ヘロンの公式はそのままだと、数値計算での安定性が良くないらしいぞ
解決策は、Wikipediaの英語版の方に…
tps://en.wikipedia.org/wiki/Heron%27s_formula#Numerical_stability
の長さ
この公式で計算される面積は、理論的には正しい値です。しかし、実際には、以下の理由で誤差が生じる可能性があります。
数値計算の誤差: 計算機で数値を扱う場合、有限桁しか扱えないため、丸め誤差が生じます。特に、辺の長さの値が大きく異なる三角形の場合、この誤差が顕著になります。
四捨五入誤差: 計算結果を小数点以下n桁まで表示する場合、n桁目以降の数字を切り捨てます。この四捨五入誤差も、面積の誤差に影響を与えます。
by Gemini
>>327に載っている参考文献
William M. Kahan, ‘Miscalculating Area and Angles of a Needle-like Triangle’
http://www.cs.berkeley.edu/~wkahan/Triangle.pdf
のTable 1の問題がパソコン等でのC++プログラムでも再現されるか試してみた。
https://ideone.com/r4toUS Table 1とは違い、Accurate Δが概ね正確な場合にHeron's Δ'が大きく懸け離れた不正確な値に
なってしまうことはなく、ほぼ同じ値になり差はごく僅かしかない。Table 1のような不安定性は
Table 1の計算に使われたプログラマブル関数電卓に特有の問題で、パソコン等のプログラムでは
再現されない。(パソコン等のdoubleの方が精度が高いので当然と言えば当然だが)
一方、(a, b, c) = (5278.64055, 94721.35941, 99999.99996)の場合は、逆にHeron's Δ' = 0が
正確なのにAccurate Δ = 9.53674324543714が大きく懸け離れた不正確な値になってしまう
重大な欠点がある。これは、Accurate Δの式の根号内の第2因数c - (a - b)が正確には0なのに
3.63797880709171e-12と計算されてしまい、この誤差が他の因数との乗算により増幅されるから。
Heron's Δ'の式の根号内の第4因数s - cは0と計算されるので問題ない。
double向けの入力値(a, b, c) = (31622.77777777662, 0.000000000023, 31622.77777777661)を
作れば、Heron's Δ' = 2.30085990753844e-07, Accurate Δ = 3.20111707955507e-07となり、
相対差は確かに大きくなるが、200ビットで計算したほぼ正確な値3.27490470056059e-07から
見れば両方とも不正確だから、Accurate Δの利点はない。
だから、パソコン等のプログラムでは改良版の式を使う必要がないどころか使うべきではなく、
ヘロンの公式をそのまま使う方が良い。
>(a, b, c) = (5278.64055, 94721.35941, 99999.99996)
>c - (a - b)が正確には0なのに3.63797880709171e-12と計算されてしまい
この例に限らず、たいていの場合a,b,cはdoubleでexactに格納されて無くて
この例では「c - (a - b)が正確には0」なのをチョイスしただけでは?
パソロジカルな三角形をパラメトライズして面積を積分する検証はどう?
数式計算での正確な値
Heronで面積計算した時の数値積分
Accurateで面積計算した時の数値積分
を比べるのがフェアかなぁと
> 200ビットで計算したほぼ正確な値3.27490470056059e-07
この例だけ見るとAccurate Δの方が優れているように見えるので
>>331の様なチェリーピックはどちらの計算式でも出来るので平均的に近似が近い方が精度的に優れているかと
>>331 その通り。そして、(a, b, c) = (10000.1, 10000.2, 20000.3)とすれば、正しい面積は0なのに
Heron's Δ' = 2.69745899635295とAccurate Δ = 1.34872949817647は両方とも大間違いになる。
この場合のようにHeron's Δ'での問題がAccurate Δで改善されないだけでなく、
>>331の引用の
場合のようにHeron's Δ'では結果的に問題ないのにAccurate Δでは新たな問題が生じてしまうのは、
参考文献の11ページで述べられた
An algorithm stood convicted of numerical instability if it could be replaced by
a new algorithm at least about as fast and accurate as the old for all data,
and good for all data for which the old algorithm was bad.
すべてのデータに対して旧アルゴリズムと少なくとも同じくらい高速かつ正確であり、
かつ旧アルゴリズムが悪くなるすべてのデータに対して良くなる新アルゴリズムによって
置き換えることができるとしたら、旧アルゴリズムは数値的に不安定と判定される。
という判定条件を満たさないから、Accurate Δは改良版としての適性を欠く。
>>333 その例では有効桁数がHeron's Δ'は0桁、Accurate Δは1桁しかなく、どちらの品質も絶対的に
劣悪で、それらの間の相対的な優劣に大した意味はない。
そもそも針のように異様に細長い三角形が重箱の隅をつつくような話で、普通はそんな場合は
想定しなくても良く、ヘロンの公式で充分。そこを敢えてつつくなら、ヘロンの公式だけでなく
改良式もぼろが出てしまうだけ。
総合すると有効桁じゃなくて精度が2桁良いし実装上は大差ないから改良版を使う、と言う方が自然では?
何でこんなに過疎化しちゃったのか。前に頻繁に出題していた人がいなくなったのか。
>>338 お題が出尽くしたってことはあるんじゃないか?
過去のお題拾ってきてそれを投稿すればいいぐらいまでスレが成熟してしまったのでは?
じゃあ10年前のこのお題(URLを書くとNGになるようなので書かない)。
プログラミングのお題スレ Part4
115 :デフォルトの名無しさん:2014/06/21(土) 18:36:45.72 ID:/fMJIWig.net
お題:文字列Aを1回以上繰り返した文字列Bが与えられたとき
文字列Aを求める。ただしAの候補が複数ある場合は最短のものとする。
例
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -> a
123412312341231234123123412312341231234123 -> 1234123
oxoxoxoxoxoxoxoxxoxoxoxoxoxoxoxoxx -> oxoxoxoxoxoxoxoxx
ttps://ideone.com/KrUq7e
Z-algorithm を使って O(|B|) で解いてみた
あれ?どんぐりの都合か?URL書いてあると書けなくなったような?
URLの先頭のhを抜いて書いてみよう。
>>343 Kotlin
こちらは普通に自作したやつ。
ttps://paiza.io/projects/OYy-A5rfKg7RqLzv-DKMIA
こちらは正規表現使ってとても小さくなったやつ。
ttps://paiza.io/projects/jgmtMRDhKfcjYfGAglEl3g
お題: コロン区切りの時分秒の時刻が与えられるので時分秒をそれぞれ掛け算した結果を表示せよ
例:
04:05:06
120
お題: バイト列が与えられる。先頭から解析した場合にバイトが1だったら次の4バイトを読み込んで整数として出力し、バイトが2だったら次のバイトを0が来るまで読み込んで文字列として出力せよ
入力
1 1 0 0 0 2 65 66 67 0 1 128 0 0 0
出力
1ABC128
>>348 Perl
bash のコマンドラインから入力して実行(ワンライナー)
$ perl -ne 'if(/(\d+):(\d+):(\d+)/){print $1*$2*$3,"\n"}else{print"入力エラー\n"}'
1:2:3
6
3:4:5
60
04:05:06
120
$
>>348 Windows のPowershell 上で、Ruby の1-liner を使う
末尾の改行を削除して、: で分割して、
文字列を数値型に変換してから、全ての要素を掛ける。
%Q で、ダブルクォーテーションをエスケープする。つまり、split(":")
echo '01:2:09' | ruby -ne 'puts $_.chomp.split(%Q[:]).map(&:to_i).inject(:*)'
18
>ruby -ne 'p eval($_.gsub(":","*"))'
1:2:9
18
お題:引数sとnを取りシーザー暗号化を行う関数を作れ
sは平文、nはずらす文字数(負数可)、返り値は暗号化後の文字列
同様の関数で「Hello, World!」を暗号化し復号化せよ
#! ruby
class String
def to_c(n)
if %r|^n|=~n
n=(n.sub(%r|^n|,"").to_i+26)%26
lb=("A".."Z").to_a.join
sb=("a".."z").to_a.join
la=lb[n..25]+lb[0..n-1]
sa=sb[n..25]+sb[0..n-1]
return self.tr(lb,la).tr(sb,sa)
else
return self
end
end
end
p "Hello,World!".to_c("n3") #=>"Khoor,Zruog!"
p "Hello,World!".to_c("n-5") #=>"Czggj,Rjmgy!"
p "Hello,World!".to_c("s") #=>"Hello,World!"
p "Khoor,Zruog!".to_c("n-3") #=>"Hello,World!"
p "Czggj,Rjmgy!".to_c("n5") #=>"Hello,World!"
#! ruby
class String
def to_c(n)
if %r|^n|=~n
n=(n.sub(%r|^n|,"").to_i+26)%26
lb=("A".."Z").to_a.join
sb=("a".."z").to_a.join
la=lb[n..25]+lb[0..n-1]
sa=sb[n..25]+sb[0..n-1]
return self.tr(lb,la).tr(sb,sa)
else
return self
end
end
end
p "Hello,World!".to_c("n3") #=>"Khoor,Zruog!"
p "Hello,World!".to_c("n-5") #=>"Czggj,Rjmgy!"
p "Hello,World!".to_c("s") #=>"Hello,World!"
p "Khoor,Zruog!".to_c("n-3") #=>"Hello,World!"
p "Czggj,Rjmgy!".to_c("n5") #=>"Hello,World!"
Haskell
範囲外の数値は平文字をそのまま返すこととした。
import Data.Char
cearsar n |(-26) <= n && n <= 26 = map (f n)
where
f x = chr.(+x).ord
cearsar _ = cearsar 0
sample:
ghci> cearsar 50 "Hello, World!"
"Hello, World!"
ghci> cearsar 3 "Hello, World!"
"Khoor/#Zruog$"
ghci> cearsar (-3) "Khoor/#Zruog$"
"Hello, World!"
TA = [ * ?\x20 .. ?\x7E ]
TS = TA.join
def caesar( s, n ) s.tr( TS, TA.rotate( n ).join ) end
s = "Hello, World!"
p caesar( s, 0 ) #=> "Hello, World!"
p caesar( s, 1 ) #=> "Ifmmp-!Xpsme\""
p caesar( s, -1 ) #=> "Gdkkn+~Vnqkc "
p caesar( s, 20240607 ) #=> "Jgnnq.\"Yqtnf#"
p caesar( caesar( s, 20240607 ), -20240607 ) #=> "Hello, World!"
p caesar( 'HAL9000', 1 ) #=> "IBM:111"
>>348 Perl5
($x = '04:05:06') =~ s/:/*/g;
print eval $x;
>>349 > 「バイトが1だったら次の4バイトを読み込んで整数として出力し、」
正直、意味がわからんかった
例で見ると
1 1 0 0 0 → 1
1 128 0 0 0 → 128
ということだが
1に続く4バイトを加算して出力するって意味だったのかいな
>>363 出題者がエンディアンを知らなくて説明もなくリトル環境を前提にしてしまっている
エンディアンを知っている人たちは出題には書かれてないけど例よりリトル前提だと読み取ってこたえている
>>365 リトルエンディアンはビットが逆って事じゃ無いぞ
10 00なら
00 10だぞ
>>365 ああそういうことか「4バイトを読み込んで整数」と書いてあるのはそういう意味だったのか
ならわかるかも。
オレは4バイト一個一個が整数だと捉えて、それを「4バイトを読み込んで整数」とは何のこっちゃと?になってたわ
>>367 例が間違えてるか説明が足りて無い
要は4バイトを読み込んでと説明してるが「一気に4バイト読み込む」とおかしくなる
1バイトずつ順に4バイトを読み込んでという説明なら例が腑に落ちる
>>356 Kotlin
面倒なのでASCIIコード(0x20-0x7e)でしかシフトしないやつを作った。
まあでも Kotlin は Java 同様に内部でUnicodeで扱っているので平仮名とか漢字とか全然違う言語の文字とかも比較的楽に追加できると思う。
https://paiza.io/projects/5H9H1zSjDnVshGCf4JaQJg お題:配管サイズの「A呼称」「B呼称」の相互変換
tps://www.keyence.co.jp/ss/products/process/flowmeter/technique/size.jsp
などに掲載されている「A呼称」から「B呼称」への変換。及びその逆変換。
「A呼称」は整数値で(8とか)、「B呼称」は実数(0.125とか)または分母を8とする分数の分子(1とか)で表すものとする。
規格に存在しない場合(42Aとか)は考慮しなくてもよい。
表を引くだけなら簡単過ぎるので、ツェラーの公式の様な「技巧的」な解法を求む。
REM 呼称変換.bat
chcp 65001
ruby -x "%~f0"
ruby tmp.rb
goto end
#~
#!ruby
#encoding: utf-8
Encoding.default_external='UTF-8'
require 'base64'
st=<<'EOS'
IyFydWJ5CiNlbmNvZGluZzogdXRmLTgKRW5jb2RpbmcuZGVmYXVsdF9leHRl
cm5hbD0nVVRGLTgnCgpjbGFzcyBPYmplY3QKICBkZWYgdG9fZmwKICAgIHJl
dHVybiBldmFsKHNlbGYuc3BsaXQoIisiKS5tYXB7fGV8CiAgICAgIGUuc3Bs
aXQoIi8iKS5tYXB7fGZ8IGYudG9fZi50b19zfS4KICAgICAgam9pbigiLyIp
fS5qb2luKCIrIikpCiAgZW5kCmVuZAoKY2xhc3MgTnVtZXJpYwogIEBAYT1b
Niw4LDEwLDE1LDIwLDI1LDMyLDQwLDUwLDY1LAogICAgICA4MCw5MCwxMDAs
MTI1LDE1MCwxNzUsMjAwLDIyNV0KICBAQGI9WyIxLzgiLCIxLzQiLCIzLzgi
LCIxLzIiLCIzLzQiLCIxIiwKICAgICAgIjErMS80IiwiMSsxLzIiLCIyIiwi
MisxLzIiLCIzIiwKICAgICAgIjMrMS8yIiwiNCIsIjUiLCI2IiwiNyIsIjgi
LCI5Il0KICBAQGM9QEBiLm1hcHt8ZXwgZS50b19mbH0KICBkZWYgYV90b19i
CiAgICBuPXNlbGYKICAgIGlmIG48MjUwCiAgICAgIGE9NgogICAgICBAQGEu
ZWFjaHt8ZXwgYT1lIGlmIGUvbjw9MS4wfQogICAgICBiPUBAYltAQGEuaW5k
ZXgoYSldCiAgICAgIGM9QEBjW0BAYS5pbmRleChhKV0KICAgICAgcmV0dXJu
ICIoYT0je2F9KSBiPSN7Yn09I3tjfSIKICAgIGVsc2UKICAgICAgYT0obi81
MCkudG9faSo1MAogICAgICBiPWEvMjUKICAgICAgcmV0dXJuICIoYT0je2F9
KSBiPSN7Yn0iCiAgICBlbmQKICBlbmQKICBkZWYgYl90b19hCiAgICBuPXNl
bGYKICAgIGlmIG48MTAKICAgICAgYz0wLjEyNQogICAgICBAQGMuZWFjaHt8
ZXwgYz1lIGlmIGUvbjw9MS4wfQogICAgICBhPUBAYVtAQGMuaW5kZXgoYyld
CiAgICAgIGI9QEBiW0BAYy5pbmRleChjKV0KICAgICAgcmV0dXJuICIoYj0j
e2J9PSN7Y30pIGE9I3thfSIKICAgIGVsc2UKICAgICAgYj1uLnRvX2kKICAg
ICAgYT1iKjI1CiAgICAgIHJldHVybiAiKGI9I3tifSkgYT0je2F9IgogICAg
ZW5kCiAgZW5kCmVuZAoKd2hpbGUgMQogIGFyPVsi77yh5ZG856ew44GL44KJ
77yi5ZG856ewIiwi77yi5ZG856ew44GL44KJ77yh5ZG856ewIiwi57WC5LqG
Il0KICBtc2c9YXIubWFwLndpdGhfaW5kZXh7fGUsaXwiI3tpKzF9OiN7ZX0i
fS5qb2luKCJcbiIpKyJcbiIKICBwcmludCBtc2crImlucHV0IG51bWJlciA+
ICIKICBuPSRzdGRpbi5nZXRzLnRvX2kKICBicmVhayBpZiBuPT0zCiAgbmV4
dCBpZiBuPT0wCiAgd2hpbGUgMQogICAgcHJpbnQgIiN7YXJbbi0xXX06aW5w
dXQgdmFsdWUgPiAiCiAgICBtPSRzdGRpbi5nZXRzLmNob21wCiAgICBicmVh
ayBpZiBtPT0iIgogICAgbT1tLnRvX2ZsCiAgICBwdXRzIG0uYV90b19iIGlm
IG49PTEKICAgIHB1dHMgbS5iX3RvX2EgaWYgbj09MgogIGVuZAplbmQK
EOS
File.write("tmp.rb",Base64.decode64(st))
__END__
:end
お題
C言語のトライグラフ(可能ならダイグラフも)と普通のテキストとの相互変換。
ファイルまたは標準入力から読んで変換した結果を標準出力に出力する。
面倒なら文字列変換する関数とそれをテストするメイン関数のみでも良い。
お題
Unicode 文字列を UTF-9 へ変換する。また UTF-9 を Unicode 文字列に変換する。
ただし1バイトが9bitではないコンピュータを使用する場合は9bit以上で扱いやすいbit数の変数(例えば 16bitの変数)を代用して下9bitのみを使用する等しても良い。
UTF-9 の仕様は RFC 4042 を見るか、または下記URLのページを参照。
https://www.wdic.org/w/WDIC/UTF-9%20%28RFC%29 お題
整数の格子がある(伝われ)
任意の2点間を線で結ぶ(座標成分は実数)
格子と交わるところで線を分割せよ
>>384 jwwの外部変形としてこんな感じで交点で分割させるの作ったことあるけどプログラミングスレののお題としては座標指定もなく漠然としすぎていていかがなものか。ちょっと伝わんなかった。
ごめん、画像から察してほしい
遊びだから曖昧なところは適当で
https://i.imgur.com/YUKpLcI.png >>386 二直線の交点は連立方程式を解けば良くて行列を使えば簡単だけど、どういう回答が求められてるのかが分からず途方に暮れております
クイズと「プログラミングのお題」との決定的な違い
検証するための入力(問題)と出力(解答)例が明記されているかどうか
テンプレに書いてなかったしいいやって思っちゃった
ここまで伝わらんもんなのか…
具体例を計算するのはめんどくさいけど、例えばさっきの絵で言えば右上が始点で左下が終点なら始点側から順番に座標を出力するとかね
入力例とその時の出力例を
データとして数種類用意すればOK
例えば
>>234とか
>>343を参考
>>390 そういうことは伝える努力をしてから言おうな
めんどくさい
そこまでして出そうと思わんから興味ないならスルーで
この頭の悪さを見るに学校の課題か何かを丸投げしようとしてるのかな
入出力例があると仕様が定まってプログラミングのお題が成立する
入出力例がないと宿題を手伝わせようとしているだけの可能性も否定できないね
>>394 ドンマイ、出題の意図は分かった気がするので改めて出題
お題
10mm方眼用紙、左下原点、入力された任意の直線と方眼線との交点を求めよ
(例)始点(3.5,5.2)終点(6.3,8.1)
お題:与えられた線分を指定された長さLで分割せよ。ただし最後に余る分は長さLでなくてもよい。
線分([始点,終点])=[[0,0],[100,100]]
L=50
↓
[[[0,0],[50,50]],[[50,50],[100,100]]]
>>399 その例おかしくない?それか問題がおかしいか。
長さがLということはx=yの線を分割する場合は座標はx, y 共にL/√2倍にならないか?
修正
線分([始点,終点])=[[0,0],[120,0]]
L=50
↓
[[[0,0],[50,0]],[[50,0],[100,0]],[[100,0],[120,0]]]
REM 座標計算.bat
chcp 65001
ruby -x "%~f0"
goto end
#~
#!ruby
#encoding: utf-8
Encoding.default_external='UTF-8'
require "matrix"
while 1
print "input start point > " #0,0
p1=$stdin.gets.split(",").map{|e| e.to_f}
print "input end point > " #120,0
p2=$stdin.gets.split(",").map{|e| e.to_f}
print "input length > " #50
l=$stdin.gets.to_f
exit if l<=0
p1[1]=0 unless p1[1]
p2[1]=0 unless p2[1]
v1=Vector.elements(p1)
v2=Vector.elements(p2)
m=(v2-v1).r
n=(m/l).to_i
a=(0..n).map{|e| l*e}
b=a.map{|e| v1+(v2-v1)*(e/(v2-v1).r)}.map{|e| e.to_a}
b<<p2
p b.uniq
end
__END__
:end
お題:今日、または任意の日付から、もういくつ寝るとお正月かを求めよ。(昼寝は除く)
>>404 bash のコマンドラインから expr コマンドと date コマンドを利用して次のようにして計算した。
実際に日数が経過後に1月1日になっているかの確認もした。
$ expr $( date -d '2024/12/31' +%j ) - $( date +%j ) + 1
132
$ date -d 'now +132 days'
2025年 1月 1日 水曜日 07:58:54 JST
$
>>407 をちょっと改良
今年に限定しないやりかた。
$ expr $( date -d $(date +%Y)'/12/31' +%j ) - $( date +%j ) + 1
132
$
てかこのお題で私、期間中にヨーロッパから帰国しますんでってな特殊ケースまで折り込めって方が無理に思えるけど、ロケール設定した模範解答をどぞ、
お題:複数の文字列が格納されている配列と配列の添字がある。標準入力からnextが入力されたら文字列を表示し添字を進め、prevが入力されたら文字列を表示して添字を戻す。添字が始点と終点に達したら始点は終点に、終点は始点に移動させる。動作は例に合うように実装せよ。
v = ["aaa","bbb","ccc"]
next
aaa
next
bbb
prev
aaa
next
bbb
next
ccc
next
aaa
>>413 REM nextprev.bat
ruby -x "%~f0"
exit
#~
#!ruby
#encoding: utf-8
i=0;v=["aaa","bbb","ccc"]
while 1
puts v[i]
print "input next or prev [n/p]> "
a=$stdin.gets.chomp
if ""==a
exit
elsif /^n/=~a
i=i+1
elsif /^p/=~a
i=i-1
end
i=(i+3)%3
end
お題
引数aから引数bまでの数列を返す関数がある。この関数を数列にゾロ目が含まれていた場合に空の数列を返すように実装せよ
>>417 windowsを使ってるんですが
>>417を実行するにはどのような環境を整えれば良いでしょうか?
417ではないが,clispかsbclをインストールすればいいよ.Windowsでもできるし,WSLならさらに簡単にできる
>>419 ありがとうございます
そうするとemacsが使えるようになるのでしょうか?
それともプログラミング言語としてのlisp環境が整うだけでしょうか?
>>418 Windowsは不断使いしていないんで開発環境とかemacsとかはわからないけど、動かすだけなら
https://www.sbcl.org/platform-table.html からWindows版のSBCLインストーラーを落としてインストール
コマンドプロンプトなどのコマンド行で
sbcl --script ファイル名 とすると「ファイル名」のファイルをスクリプトとして実行します
--script を付けない場合REPLが起動します(Pythonでいうところの対話モード)
これの終了は (quit) と入力してEnterキー
ちょっと試すだけならウェブサービスを使う手も
Common Lispを動かせるオンラインコンパイラーサイト
https://rextester.com/l/common_lisp_online_compiler https://www.jdoodle.com/execute-clisp-online https://wandbox.org/ これらはideoneとは異なり "Share" とか "Save" とかをクリックしない限り保存・公開されない(はず)
レス頂いた方、ありがとうございます
とりあえず
>>422辺りで試してみます
REM zorome.bat
ruby -x "%~f0"
exit
#~
#!ruby
while 1
print "input a > "
a=$stdin.gets.chomp
exit if a==""
a=a.to_i
print "input b > "
b=$stdin.gets.to_i
ar=(a..b).to_a
z=0
ar.each{|e|
n=e.to_s.gsub(/^-/,"")
m=n.split("").uniq
if n.size>1 && m.size==1
z=1
break
end
}
ar=[] if z==1
p ar
end
__END__
a=0;b=10 => [0,1,2,3,4,5,6,7,8,9,10]
a=0;b=11 => []
>>416 fn is_zorome(n: i32) -> bool {
let s = n.abs().to_string();
let b = s.as_bytes();
if b.len() > 1 {
b[1..].iter().all(|&d| d == b[0])
} else {
false
}
}
fn odai(a: i32, b: i32) -> Vec<i32> {
if (a..=b).any(|n| is_zorome(n)) {
vec![]
} else {
(a..=b).collect()
}
}
fn main() {
assert_eq!(odai(1, 10), [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
assert_eq!(odai(1, 11), []);
}
>>416 Kotlin
(URL投稿禁止になってるようなので先頭の https:// は抜きで)。
paiza.io/projects/nPK7U1uDtt4b7O2saECP0A
[入力]タブの方で開始、終了の値を入れている。とりあえず 10 40 を入れてある。
一桁の数を指定した場合は全てゾロ目扱いになるので出力は空のリストになる。
お題:文字列を中央寄せする関数を作れ。
関数は文字列、全体の横幅(整数)、余白を埋める文字、を引数に取る。横幅分の文字列を引数の文字で作成し、その中央に引数の文字列を埋め込み戻り値として返せ。
>>427 文字幅についてはどう考えれば良い?
エンコーディングが UTF-8 や UTF-16 だとバイト数や要素数が画面の表示幅と一致しないわけだが。
一致するような Shift-JIS だったとしても端末のフォント設定次第で表示幅が変わる。
asciiの前提では
全角判定関数は切り分けるべきだし
#ドラクエ3が超好きだったので、お題にしてみる。ただしロト3のファミコン版のドラクエな!w
"こちらの職業は勇者、戦士、空手家、僧侶、柔道家の5人がかりw
勇者から柔道家までの5人の攻撃回数が異なります。"まずは変数と確率の問題。
勇者=you戦士=sen,空手家=kara,僧侶=sou
まず勇者は1~2回攻撃、戦士は1~3回攻撃、空手は2~3回攻撃、柔道は足払いで相手を20%で麻痺させることができる。(1ターン何もできない)10%では超麻痺。(2ターン何も敵は動かない)
5%でクリティカルヒットの足払いで3ターン敵は何もできない。
柔道は敵に攻撃を加えられない分、足払いで相手を痙攣させる。
(勇者の1回分の攻撃は100〜200、20%の確率でクリティカルヒットの攻撃になることがある。
(戦士の攻撃は200〜300、20%の確率で攻撃がクリティカルヒット1回になることがある。
(空手家)空手家の攻撃は350〜500、ただし20%の確率で攻撃がクリティカルヒットとなるときがある。youはぞろ目(111とか222とか999まで)の場合はロトの剣を取得する。
攻撃回数無限で全てクリティカルヒットになります。
クリティカルヒットは攻撃力X2です。さてプログラムをやっていくか。"
*ただし、ロトの剣は勇者しか使えない。
”まずギルガメッシュっていう名前のenemy
ラスボスの名前はenemyとする。ボスのHPは5万。
ボスは基本的に何もしません、できません。これやるとさすがに面倒なのでw
基本的にボスは攻撃しません。(面倒だからw)
一方的になかまあつめてボコすw”
*ロトの剣で攻撃したら攻撃力が1.5倍あがります。*
**癒しの穂。食べたら防御力と賢さがあがります**
ロトの剣の出現条件は3並びで一つ食べることができます。
例えば111攻撃とか222攻撃とか333攻撃とか〜999まで。
次の発言からコードを書いていく。
ニーズあるか?
しまった。初期化してなかったなw変数のところ。
あとsouの回復もホイミ、ベホイミ、ベホマラーの3種類だけ。
その3種類がぞろ目の時(111,222など)
そしたらベホマズンを使える。ほぼ運ゲーですw
人修羅みたいに取り巻きがいます。それはバラモスエビルと神龍です。
ある一定時期を過ぎると取り巻きが一斉にHPを連続してあげまくるので
取り巻き先に倒さないと厳しいです。取り巻き=tori種類1の取り巻き=tori0
種類2の取り巻き=tori1 5人だとなかなか倒せないから6人目の魔法剣士=maken
だれか
これをいれよう。
さてif文を完成させよう!if zoma =1
print("ゾーマが現れた”)
import random
random.random()x = random.uniform(0.1,0.9)
print(x)
if x >200 :
print( 'enemyに' +200のダメージを与えた)
elif x > 0.5 :
print( 'enemyに100+のダメージを与えた' )
elif x > 0.2 :
print( '相手が躱した' )
else :
print( "まだゾーマは死んでません")
つかれたーw
もっと簡単なやつにしまーすw
頑張って読んだけどこのままでは多分スレチ、ずっと条件を簡単にして出題し直してみる。
お題
勇者(HP1000)対魔王(HP5000)、先鋒勇者、サイコロ(目は1から6)を振って出た目だけ相手にダメージを与えられ、交互に攻撃しHP0となったら負け。魔王のサイコロは1個だけど勇者のサイコロはN個(N=1~10)の時の勇者の勝率を求めよ。
# RPGの攻撃状況を再現
# モンスターと戦っている。
# 1から10のサイコロをふって、
# 6未満の場合、サイコロの目だけダメージを与えたと表示。
# 6以上の場合、クリティカルヒットとして、100のダメージを与えたと表示。
# 0の場合、防御されたとして、0ダメージを表示。
import random
hit = random.randint(0,10)
if 1 <= hit < 6:
print("スライムに、" + str(hit) + "のダメージを与えた!")
elif hit >= 6:
print("クリティカルヒットダメージ100を与えた")
else:
print("ダメージは、" + str(hit) + "防御された")
#楽しすぎだなwこれはw
お題:文字列の中で1つ以上連続している空白をすべて空白4つに置換せよ。ただし正規表現は使ってはならない。
例:
"abc def ghi" -> "abc def ghi"
5chは空白を1つに置換するらしく例は出せない。脳内保管せよ。
>>438 perl -lpE'$_=join$"x4,split$"'
(文字列を入れる)
>>440 splitのあとの$"は不要だった。
どちらにしてもタブも置換してまうのでアウトかも。
>>435 こういう場合の確率の計算はよく分からなかったので実際にそれぞれ一万回ずつ戦わせてみた。
サイコロ1個で100000戦0勝
サイコロ2個で100000戦0勝
サイコロ3個で100000戦0勝
サイコロ4個で100000戦0勝
サイコロ5個で100000戦47171勝
サイコロ6個で100000戦100000勝
サイコロ7個で100000戦100000勝
サイコロ8個で100000戦100000勝
サイコロ9個で100000戦100000勝
サイコロ10個で100000戦100000勝
>>443 #!ruby
#encoding: utf-8
$stdout=open("kekka.txt","w")
i=100000 #対戦回数
k=0 #勇者の勝ち
n=1 #勇者のサイコロの数
hpm=5000 #魔王のHP
hpy=1000 #勇者のHP
>>444 while n<=10
j,t=0,0
while j<i
hpy-=rand(1..6)
if hpy<=0
j+=1
t,hpy,hpm=0,1000,5000
next
end
m=0
while m<n
hpm-=rand(1..6)
m+=1
end
if hpm<=0
k+=1
j+=1
t,hpy,hpm=0,1000,5000
next
end
t+=1
end
puts "サイコロ#{n}個で#{i}戦#{k}勝"
k,hpy,hpm=0,1000,5000
n+=1
end
>>427 Kotlin
スペースが何個なのか分り易くするために '*' をスペースの代わりに入れて呼び出している。
https://paiza.io/projects/xSP0nP203HXTwqyxlQD0Gg >>435 R
f=\(N){
u=1000
m=5000
while(u>0 & m>0){
m=m-sum(sample(6,N,replace=TRUE))
u=u-sample(6,1)
}
u>m
}
sim=\(N) mean(replicate(1e3,f(N)))
p=sapply(1:10,sim)
plot(p)
data.frame(N=1:10,p=p)
N p
1 1 0.000
2 2 0.000
3 3 0.000
4 4 0.000
5 5 0.498
6 6 1.000
7 7 1.000
8 8 1.000
9 9 1.000
10 10 1.000
>>435 Wolfram
f[N_] :=(
u=1000;
m=5000;
Until[u<=0 || m<=0, m-=Total@RandomChoice[Range[6],N];u-=Total@RandomChoice[Range[6],1]];
Boole[u >= m]
)
Table[Mean@Table[f[x],10^3],{x,1,10}] // N
{0., 0., 0., 0., 0.511, 1., 1., 1., 1., 1.}
ベクターにあるこれを解いてくれ
昔2ch、5chスレでやってたができず
いまだと4x4はパワーで行けるとおもうが
4x4盤タイルゲーム for Windows
対戦するたびに学習して次第に強くなる「最善手探索+対戦学習型知能ゲーム」
>>449 勝手に名付けて水道管連結ゲーム
先後で縦か横で管を繋げた方の勝ち
ただしこの場合、黒が角においたら連結するだけだが今白が角におくと黒2つは除去される
▓
□▓
>>449 解いてくれって?何をしたらいいの?
全パターンやらせて勝つパターンを出せってこと?
お題
AのあとbノAと同じ数だけBが続く言語エビがあるとします
文字列が入力されたときそれがエビ言語であるか判定するプログラムを作成してください
→ true
A → false
B → false
AB → true
ABB → false
AAB → false
AABB → true
ABAABBAAABBB→ true
>>464 文字化け訂正
誤:AのあとbノAと同じ数だけBが続く言語エビがあるとします
正:AのあとにAと同じ数だけBが続く言語エビがあるとします
>>464 fn is_ab_lang(input: &str) -> bool {
match input
.chars()
.fold(Some(0), |state, char| match (state, char) {
(Some(count), 'A') => Some(count + 1),
(Some(count), 'B') if count > 0 => Some(count - 1),
_ => None,
}) {
Some(0) => true,
_ => false,
}
}
fn main() {
for s in ["", "AB", "AABB", "ABAABBAAABBB"] {
assert!(is_ab_lang(s)); // true
}
for s in ["A", "B", "BA", "ABB", "AAB", "ABBA"] {
assert!(!is_ab_lang(s)); // false
}
}
>>464 c
https://ideone.com/KDcKNc #include <stdio.h>
#include <string.h>
int isablang(const char *s) {
size_t a = strspn(s, "A"), b = strspn(s + a, "B");
return !*s || 0 < a && 0 < b && a == b && isablang(s + a + b);
}
void g(const char *s) {
printf("%s\t%s\n", isablang(s) ? "true" : "false", s);
}
int main() {
g("A"), g("B"), g("C"), g("BA"), g("CA"), g("ABB"), g("AAB"), g("AABABB"), g("ABC"), g("CAB"), g("ABCAB");
g(""), g("AB"), g("ABAB"), g("AABB");
return 0;
}
>>468 ChatGPTロジックだとAABABBが受理されちゃう
>>464 c
https://ideone.com/x7a81M ・strspn使わない
・再帰しない
#include <stdio.h>
int isablang(const char *s) {
const char *t, *u;
for (; *s; s = u) {
if (*s != 'A') return 0; else for (t = s; *t == 'A'; t++);
if (*t != 'B') return 0; else for (u = t; *u == 'B'; u++);
if (t - s != u - t) return 0;
}
return 1;
}
お題
貨幣・銀行券を次の文字列で表すとします
(1)
(5)
(10)
(50)
(100)
(500)
[1000]
[5000]
[10000]
貨幣・銀行券がランダムに次のような文字列で与えられます
(100)(10)(1)[10000](5)(500)[1000][5000][1000][1000](10)(100)(50)(100)[1000]
与えられた貨幣・銀行券を分類して貨幣・銀行券の価値が高い順に次のように出力するプログラムを作成してください
[10000]
[5000]
[1000][1000][1000][1000]
(500)
(100)(100)(100)
(50)
(10)(10)
(5)
(1)
>>449 誰もいないので自分でAIに司令してやってみた
が何かおかしい
https://ideone.com/ZlulrF 4*4タイルゲームをAIに命令させてやらせているが
それっぽいのを出力はするが正しい勝利判定ができていない
>>474 Perl5
$s = '(100)(10)(1)[10000](5)(500)[1000][5000][1000][1000](10)(100)(50)(100)[1000]';
$h{$_} .= $_ for $s =~ /\(\d+\)|\[\d+\]/g;
use List::Util 'sum';
$v{$h{$_}} = sum($h{$_} =~ /\d+/g) for keys %h;
print "$_\n" for sort{$v{$b} <=> $v{$a}} keys %v;
実行結果
~ $ perl 22_474_value.pl
[10000]
[5000]
[1000][1000][1000][1000]
(500)
(100)(100)(100)
(50)
(10)(10)
(5)
(1)
>>483 Perl5
$_ = 'abc def ghi';
print join(' ' x 4, split) . "\n";
お題
文字列と長さを入力として受け取り
デカルト積のリストを出力してください
入力:ABC 1
出力:[A, B, C]
入力:ABC 2
出力:[AA, AB, AC, BA, BB, BC, CA, CB, CC]
入力:ABC 3
出力:[AAA, AAB, AAC, ABA, ABB, ABC, ACA, ACB, ACC, BAA, BAB, BAC, BBA, BBB, BBC, BCA, BCB, BCC, CAA, CAB, CAC, CBA, CBB, CBC, CCA, CCB, CCC]
>>485 Rust
fn odai(文字列: &str, 長さ: usize) -> Vec<String> {
use itertools::Itertools;
(0..長さ)
.map(|_| 文字列.chars())
.multi_cartesian_product()
.map(String::from_iter)
.collect()
}
fn main() {
assert_eq!(odai("ABC", 1), ["A", "B", "C"]);
assert_eq!(odai("ABC", 2), ["AA", "AB", "AC", "BA", "BB", "BC", "CA", "CB", "CC"]);
assert_eq!(odai("ABC", 3), ["AAA", "AAB", "AAC", "ABA", "ABB", "ABC", "ACA", "ACB", "ACC", "BAA", "BAB", "BAC", "BBA", "BBB", "BBC", "BCA", "BCB", "BCC", "CAA", "CAB", "CAC", "CBA", "CBB", "CBC", "CCA", "CCB", "CCC"]);
}
>>485 ruby
https://ideone.com/EA8orq f = ->(s, n) {:product.to_proc.(*[s.chars]*n).map(&:join)}
>>485 Rust 今回は積ライブラリを使わない自力版
fn odai(文字列: &str, 長さ: usize) -> Vec<String> {
let chars = 文字列.chars().collect::<Vec<_>>();
let mut state = vec![0; 長さ];
let mut output = Vec::new();
'Loop: loop {
let s = state.iter().map(|i| chars[*i]).collect();
output.push(s);
for index in state.iter_mut().rev() {
*index += 1;
if *index == chars.len() {
*index = 0;
continue;
}
continue 'Loop;
}
return output;
}
}
検証用main()は
>>486と同じ
>>485
JavaScript
const prod = function* (str, len, buf = [])
{
if (len > 0)
{
for (let i = 0; i < str.length; i++)
{
buf.push(str[i]);
yield* prod(str, len - 1, buf);
buf.pop();
}
}
else
{
yield buf.join("");
}
};
for (let n = 1; n < 4; n++)
{
console.log([...prod("ABC", n)]);
} >>485 Perl5
for $n (1..3) {
@cp = @s = qw(A B C);
while(--$n) { @cp = map{ $p = $_; map{ "$p$_" } @s } @cp }
print "@cp\n";
}
※見易くするためインデントは全角スペースに置換してあります
実行結果
~ $ perl 22_485_CartesianProd.pl
A B C
AA AB AC BA BB BC CA CB CC
AAA AAB AAC ABA ABB ABC ACA ACB ACC BAA BAB BAC BBA BBB BBC BCA BCB BCC CAA CAB CAC CBA CBB CBC CCA CCB CCC
>>464 Perl5
for (<DATA>) {
chomp;
print "$_ → ", (/^(A((AB)?|(?1))B)+$/g ? 'true' : 'false'), "\n";
}
__DATA__
A
B
AB
ABB
AAB
AABB
ABAABBAAABBB
ABC
AABABB
※見易くするためにインデントを全角スペースに置換してあります
実行結果
~ $ perl 22_464_AB_rec_rex.pl
→ false
A → false
B → false
AB → true
ABB → false
AAB → false
AABB → true
ABAABBAAABBB → true
ABC → false
AABABB → false
>>492 /g の gは不要で / でおkだった…orz
お題
入力された文字列から重複する文字を抽出してください
T →
CG →
ATA → A
CGGA → G
ATGAT → AT
GTTGCA → GT
CCCCGGG → CG
ACTGCGAG → ACG
ATCAGAATA → AT
TGCCATGACA → TGCA
Perl5
for (qw{T CG ATA CGGA ATGAT GTTGCA CCCCGGG ACTGCGAG ATCAGAATA TGCCATGACA}) {
%h = (); $h{$_}++ for split '';
print "$_ → ", (grep{1 < $h{$_}} keys %h), "\n";
}
※見易くするためインデントを全角スペースに置換してあります
実行結果
~ $ perl 22_500_dupe_char.pl
T →
CG →
ATA → A
CGGA → G
ATGAT → TA
GTTGCA → GT
CCCCGGG → CG
ACTGCGAG → GAC
ATCAGAATA → TA
TGCCATGACA → TGAC
CopilotのURLをコピペしても他の人に内容を見せることはできなかったワ…orz
>>500 octave
https://ideone.com/eLcVPC function s = f(s)
[~, ia] = unique(s);
s(ia) = [];
if 1 < length(s)
[~, ia] = unique(s, 'first');
s = s(sort(ia));
end
end
>>500 ruby
https://try.ruby-lang.org/playground/#code=f+%3D+-%3Es+%7Bs.chars.tally.select+%7B1+%3C+_2%7D.keys.join%7D%0Ass+%3D+%3C%3CEOS.lines(chomp%3A+true)%0AT%0ACG%0AATA%0ACGGA%0AATGAT%0AGTTGCA%0ACCCCGGG%0AACTGCGAG%0AATCAGAATA%0ATGCCATGACA%0AEOS%0Aputs+ss.map+%7B%7Cs%7C+%22%23%7Bs%7D+-%3E+%23%7Bf.(s)%7D%22%7D&engine=cruby-3.3.0
https://ideone.com/9E5Z9a f = ->s {s.chars.tally.select {1 < _2}.keys.join}
>>500 REM 重複チェック.bat
ruby -x "%~f0"
exit
#~
#!ruby
while 1
print "> "
a=$stdin.gets.chomp.split("")
exit if a==[]
puts a.select{|e| a.count(e)>1}.uniq.join
end
お題
ソース文字列と検索文字列が入力されます
検索文字列の文字をすべて含むソース文字列の部分文字列のうち
一番短い部分文字列を出力してください
DHBICEJAFG EIC → ICE
FDGJHCBIEA EIC → CBIE
FBHDCIJGEA EIC → CIJGE
JDIBGHCEAF EIC → IBGHCE
JBCIAGDHEF EIC → CIAGDHE
EJFBCAGIHD EIC → EJFBCAGI
IADCGJFBEH EIC → IADCGJFBE
IDFHBJGAEC EIC → IDFHBJGAEC
>>500 c
https://ideone.com/LLFaOP ・unsigned int m[128] = {0};を使って集計
高速文字列解析の世界に似た問題のアルゴリズム(ウェーブレット木)が沢山ありました
このスレでいいのかわからんのだけど
Rust勉強中なんだがメモリ安全性の恩恵を受けやすいなんかしらかのプログラムを書こうと思ってるんだがなにかいいお題はあるか?
言語処理系は大体作ってるのでそれ以外で頼む
う~んこの嫌われムーブはあのおじさんか
このスレでは自重して欲しいな
>>514 へのお題
次の操作ができる循環リンクリストを作成してください
・空のリストへの挿入
・冒頭の挿入
・最後に挿入
・指定された位置への挿入
・最初のノードを削除する
・最後のノードを削除する
・任意の位置からノードを削除する
>>514 Rustはメモリのデータ競合もデータ参照競合も全てコンパイルエラーにしてくれるから間違えようがないね
他の普通の言語だと実行して問題発生に気付いて調査して頑張ってようやく競合が原因だと判明して間違えていたことがわかるから開発効率の悪さとして差が現れるけど
Rustは実行前にその種のミスのデバッグまで全て終えてしまう感じ
>>518 グローバル変数を排他制御せずに使ってしまっていたりするミスなどよく見かけるような
一般的にも巨大なコードになったり複数人で共通認識なかったりで見逃しミスは必ず出てくる
そしてタイミング次第によって稀にバグが起こるパターンとか負荷が高くなって起きてバグ発覚とか
全て自分で出来る気付くミスらない
って自己過信な人がセキュリティホールを招いてるからね
自動的にサポートしてくれる言語を使うのが安全で開発効率もいいよ
ちゃんとルールを守って運転すれば
事故も起きないし、違反で捕まらない
それと同じ
>>517 せっかくだからRustで
>>516やってきなよ
>>510 c
https://ideone.com/tdT1q2 ・若干の高速化
部分文字列を一文字ずつズラして検証していたのを
n = strcspnで探してn文字スキップへ
>>516 横からだがその仕様ならベクタをリングバッファとして使った両端キューで十分だな
多くの実用例でもこの方が速いことが知られている
use std::collections::VecDeque;
// 空のキュー
let mut deque: VecDeque<T> = VecDeque::new();
// 先頭に挿入
deque.push_front(t);
// 最後に挿入
deque.push_back(t);
// 指定位置に挿入
deque.insert(index, t);
// 先頭を削除して得る
let first: Option<T> = deque.pop_front();
// 最後を削除して得る
let last: Option<T> = deque.pop_back();
// 指定位置を削除して得る
let element: Option<T> = deque.pop_back();
Rustのメモリ安全性を確認するためにプログラム書きたいんでしょ、だったら循環リストをフルスクラッチするしかないよね
リンクリストならindex番目の操作(挿入or切除)は
index番目で分解して操作して合体するだけなのでこれで動くよ
use std::collections::LinkedList;
trait LinkedListExt<T> {
fn insert_at(&mut self, index: usize, value: T);
fn remove_at(&mut self, index: usize) -> Option<T>;
}
impl<T> LinkedListExt<T> for LinkedList<T> {
fn insert_at(&mut self, index: usize, value: T) {
let mut tail = self.split_off(index);
self.push_back(value);
self.append(&mut tail);
}
fn remove_at(&mut self, index: usize) -> Option<T> {
let mut tail = self.split_off(index);
let value = tail.pop_front();
self.append(&mut tail);
value
}
}
>>510 c
https://ideone.com/L4xIAy ・f_529 は529さんのパクり
・f_strcspn_chr は strchr してから strcspn すると単純ながら若干の速度向上
>>510 c
https://ideone.com/Mar3S7 ・f_529direct は出現位置集めるのやめた
*min = strchr(*min + 1, **min)) でそのまま次へ
>>510 C++
https://ideone.com/ywT3qw >>529からの変更点
・sへのtの文字の出現位置を高速取得(1バイト文字のみに対応)
・sにtの同一文字が3回以上連続して出現する場合に最初と最後以外の位置を省略
>>500 Wolfram Language
str = "ATGAT"
>> Out[1]= ATGAT
duplicates = str // Characters \
(* { A, T, G, A, T } *) \
// Counts \
(* <| A -> 2, T -> 2, G -> 1 |> *) \
// Select[Function[ 1 < # ]] \
(* <| A -> 2, T -> 2 |> *) \
// Keys \
(* { A, T } *) \
// StringJoin (* "AT" *)
>> Out[2]= AT
>>537 しくった、これ一番短い範囲ではなく間違って一番長い範囲を検出してる。
サンプルデータではたまたま同じ解になるようで、間違いを見落としてしまった。
それから、一番長い(短いにすべきだったが)範囲の検索にわざわざ候補listをsortして[0]番目を
取得しているが無駄だし規模が大きくなると効率よくない
時間あったら直しますわ〜
>>538 あーでも527の方式がいまんとこ一番早いんだな、検証thx
>>540 >>537さん方式は動的にメモリとらなくていいのがいいよね、清々しくていいよね
あと実行時間の値はまぁアテにはならんので参考程度にw
>>500
PowerShell
"T", "CG", "ATA", "CGGA", "ATGAT", "GTTGCA", "CCCCGGG", "ACTGCGAG ", "ATCAGAATA", "TGCCATGACA" |% {
"$_ → $(-join ([char[]]$_ | group -case |% {$_.name[$_.count -le 1]}))"
}
[実行結果]
T →
CG →
ATA → A
CGGA → G
ATGAT → AT
GTTGCA → GT
CCCCGGG → CG
ACTGCGAG → ACG
ATCAGAATA → AT
TGCCATGACA → TGCA >>510 Perl5、
>>537 の修正版
https://ideone.com/klqLux 修正点
・
>>537では間違って一番長い範囲を検出していたが、一番短い範囲に修正した。(サンプルデータではそれらの解はたまたま一致)
・パターンが3文字であることに依存する定数「2(=3 -1 )」をハードコードしている箇所があったので、パターン文字数次第で処理するように修正
・検出した候補文字列リストのうち一番短い物の検索のためにわざわざ候補リスト全体をsortするのをやめて
reduceによって長さが一番短い文字列を検索するように修正
List::Utils は言語処理系にデフォルトで付属のコアモジュール、
List::MoreUtils はCPANのオプションノジュールだがideoneのperlにはインスコされていたので使っちゃいましたテヘペロ
なお、候補文字列リストを作らず、ループの最内ifの中で一番短い文字列だけを記録していく様に記述すれば
大規模問題で若干効率が良くなるだろうけど、
まあいいや、もういいや。
>>544 List::Utils → List::Util ね。スマソ
>>510 Wolfram Language
s = "DHBICEJAFG"
>> Out[1]= DHBICEJAFG
pattern = "EIC"
>> Out[2]= EIC
shortestMatch = \
(* 全通りの部分文字列を生成する *) \
ReplaceList[ Characters[ s ], {___, x__, ___} -> {x} ] \
(* 短い順、先頭に近い順に並べる *) \
// Sort \
(* 検索文字列の文字を全て含むものを選ぶ *) \
// Select[ ContainAll[ Characters[ pattern ] ] ] \
(* 1つ目を文字列として返す *) \
// Extract[ 1 ] // StringJoin
>> Out[3]= ICE
>>510 Perl5、
>>544 をもう一回だけ改良
https://ideone.com/YkuK1w 改良点:
・検出された範囲の候補を一通りリストに蓄えて、あとでその中から最短のものを探す方式を止めて、
範囲を検索するループ内のifでその時点までの最短な範囲の判定と記録を行うようにした。
・CPANモジュールList::MoreUtilsのminmaxを使わない。
・コアモジュールList::Utilはminだけ使う。reduceは使わない。
なんだかPerlのコードらしい感じが減って、ベタな感じのコードになってしまいました
>>510 C++
https://ideone.com/7EHx0H >>534からの変更点
・minmax_elementを呼び出さずに済むようにして高速化
>>510 C++
https://ideone.com/TluWQi >>548では検索文字列が短くて高速化されたか分かりにくかったので、長くして529, 534, 548の
実行時間を比較してみると、効果が顕著に現れた。
>>510 c
https://ideone.com/D2AZMK ・両端に着目し、両端のみを更新しつつ調べていく(が、これといってパっとせず)
・f_both_ends はあくまで元の文字列s上を調べていく
・f_both_ends_v2 は「次」「隣」にアクセスしやすくした構造の上を調べていく
・あと実行時間の値ははげしくブレブレなので参考程度にとどめておいてね
>>510 https://ideone.com/46Tb28 >>549の実行速度比較に554を追加。548は不要な2行を削除した。検索文字列が短いのと長いのの両方をテスト。
動画再生回数、登録者数、評価数、コメント数
上2桁、下2桁に04、13、40、44、71、74など
(+生年月日、IDの数字など)の組み合わせ
業者による忌み数字、不吉数字の嫌がらせ&精神攻撃がキモすぎ
糖質でしょ
忌み数字不吉数字とか意味不明なこと言ってるし,それを業者が特定個人を狙って表示する意味も分からんし
お題
数列が入力されます
ニ番目に小さい数を出力してください
入力:4, 5, 1, 7, 1, 2, 8, 9, 2, 7
出力:2
こんちゃ
質問いいでしょうけ
プルダウン(ポップアップ)をUIとしてだすとして
見えている項目名と、実際にパラミータとして出す値を変えたい時はどうしたらよか
>>561 Perl5
$h{$_} = $_ for 4, 5, 1, 7, 1, 2, 8, 9, 2, 7;
@s = sort keys %h;
print "$s[1]\n";
実行結果
~ $ perl 22_561_second.pl
2
Perl5.26以降に付属のList::Utilにはuniq関数があるのでそれを使えば:
use List::Util qw(uniq);
@s = uniq sort 4, 5, 1, 7, 1, 2, 8, 9, 2, 7;
print "$s[1]\n";
>>562 環境や言語やフレームワークを書いて限定しないと色々な環境や言語やフレームワークでの答えが適当に沢山湧いて出て来る可能性あるぞ。
しかも分からない所は適当に解釈してだ。なぜならここはお題スレだから。
>>561 #!ruby
puts $stdin.gets.chomp.split(",").map{|e| e.to_i}.uniq.sort[1]
>>568 全然だめでした
取りあえずテスト追加済
数列が入力されるので
整数の数列だけでなく浮動小数点数の数列にも対応してくださいね
ニ番目に小さい数がない時
例えば同じ数しか存在しない時や数列の長さが1の時には
解がないことを返してくださいね
例えばその時にMAX値が返ってきたら失格ですよ
>>571は出題者ではないよ
出題者として申し上げるなら
>>571は観点がダサい
小数対応はともかく
max値を返してしまう人はプログラマ失格かな
あとsortを使ってしまう人は計算量を知らない初心者
そういうこだわりはアスペルガーにしか思えないな、どうでも良いじゃないですかそんなこと
こだわりは自分の胸のうちに留めていただきたい、他人に求めたら回答の幅を狭めるだけ、多様性のある回答こそ美しい
>>576 多くの人はちゃんとnilとかemptyとかNoneなどを返しているよね
プログラマならそこだけは守らなければならない必須事項
だからそういう、こうじゃないとダメだという態度がアスペルガー仕草なんだってばよ、君が思うのは勝手だが他人に求めるものじゃない
プログラミングはもっと自由なものなんだよ、思ったとおりにかけば良い
そういう条件は回答を見て思いついた後から言わず先に書くべきでは?
そうでなければ、与えられた短い文とテストデータから、
処理対象データの範囲や要求仕様を読み手が色々解釈しても仕方ないだろ。
後からいろいろ言って批判なんてでもってのほかだと思うが。
出来たもの見て実はこういう条件がありましたってケチつけるのはクソクライアントと一緒だな
ざっと見たけどmax()を返してるのはC++の人だけで他は皆まともだ
普段からまともなコード書いてるかどうかバレてしまうから自由が面白い
好きにしたら良いんやで吉田松陰もそんなこと言ってた気がする
まともとかバレるとかそういう当て擦りの嫌味ったらしい言い方どこで身につけてきたのあんた、母ちゃんは悲しいよ
>>583 関数がINT_MAXを返すのはまともなコードだろ。2番目に小さい数はINT_MAXではありえないから、
返り値がINT_MAXの場合は「なし」と表示すれば良いだけ。
「データが二個未満の場合にはnilを返す。」とか書いとくべき。
でもそういう細かい条件をちまちま指定した窮屈な課題は、つまんなくて回答を造る意欲が減るんだよな。
シンプルで純な課題に対してどういうエレガントでエッセンシャルな回答があるか考えるのが楽しいのであって、
細かいいろんな条件を守る周辺コードで固めるような作業はつまんないから趣味の世界ではやりたくないな
普段はプログラム載せるだけだけど、みんな意外と饒舌なんだなw
ここはある意味、回答のコードでもって語るスレだからな
お題にそんな指定ないのに
みんなnilなどを返してるからこのスレの住人たちはセンスいいな
>>561, 571
>>570のC++のf3をint型の最大値を含むデータにも対応させた。
C#にはint?型があるのですっきり書けるが、
https://ideone.com/oRhDL1 C++ではまあまあすっきり書くにはintへのポインタを返すしかないか。
https://ideone.com/xYnTSD (該当値が複数の位置に存在する場合にそれらのうちのどれへのポインタを返すかについては
こだわらないものとする)
お題:ランダムな数列から任意の並んでいる二つの数同士を足して、その二つの数の間に挿入せよ。
その新しい数が一桁ならそのまま挿入し二桁なら桁同士を足してその二桁の間に挿入せよ。
< 123456789 3 4
> 1237456789
(3+4=7)
< 123456789 6 7
> 123456143789
(6+7=13 1+3=4)
>>594 ruby
a=$stdin.gets.chomp.split(" ")
b=a[1].to_i+a[2].to_i
c=(b<9 ? a[1]+b.to_s+a[2] : a[1]+"#{b/10}#{b/10+b%10}#{b%10}"+a[2])
puts a[0].gsub(a[1]+a[2],c)
>>594 Perl5、見易くするためインデントは全角スペースに置換してあります
for (<DATA>) {
($s, $a, $b) = split;
$c = $a + $b;
$c = $1 . ($1 + $2) . $2 if $c =~ /(\d)(\d)/;
$s =~ s/$a$b/$a$c$b/g;
print "$s\n";
}
__DATA__
123456789 3 4
123456789 6 7
123456789 8 9
3141592653589793238462643383279502884197169399375105820974944 9 7
実行結果
~ $ perl 22_594.pl
1237456789
123456143789
123456781879
3141592653589176793238462643383279502884191767169399375105820917674944
>>594
題意が以下の通りだとして、PowerShell (エラーチェックは省略)
自然数x, i, j (i + 1 = jを満たす) が与えられる。xの上i桁目の数字をx[i]で表す。
x[i]とx[j]の和をyとして、
・yが1桁のとき、yをx[i]とx[j]の間に挿入せよ
・yが2桁のとき、y[1]とy[2]の和をy[1]とy[2]の間に挿入してから、yをx[i]とx[j]の間に挿入せよ
function f($x, $i, $j)
{
$s = [string]$x
$y = [int][string]$s[$i - 1] + [int][string]$s[$j - 1]
if ($y -lt 10) {
$s.insert($i, $y)
} else {
$s.insert($i, 11 * $y)
}
}
(123456789, 3, 4), (123456789, 6, 7) |% {
"< $($_[0]) $($_[1]) $($_[2])"
"> $(f $_[0] $_[1] $_[2])", ""
}
[実行結果]
< 123456789 3 4
> 1237456789
< 123456789 6 7
> 123456143789 数学屋さんかいなw
i,jの「3 4」とか「6 7」は桁の位置をしていしているのではなく数値列の中にある数字を指定するんジャマイカ
とオレは解釈したが
>>599
そうか。だとすれば、
function f($x, $i, $j)
{
$s = [string]$x
$y = $i + $j
if ($y -ge 10) {$y *= 11}
$s -replace "$i$j", "$i$y$j"
}
(123456789, 3, 4), (123456789, 6, 7), (123456789, 8, 9), ("3141592653589793238462643383279502884197169399375105820974944", 9, 7) |% {
"< $($_[0]) $($_[1]) $($_[2])"
"> $(f $_[0] $_[1] $_[2])", ""
}
[実行結果]
< 123456789 3 4
> 1237456789
< 123456789 6 7
> 123456143789
< 123456789 8 9
> 123456781879
< 3141592653589793238462643383279502884197169399375105820974944 9 7
> 3141592653589176793238462643383279502884191767169399375105820917674944 なんでこの人はコーデイングするのがこんなに早いんだろう…
>>594 Rust
fn f(input: &str, a: u32, b:u32) -> String {
let src = format!("{a}{b}");
let dst = if a + b < 10 {
format!("{a}{x}{b}", x = a + b)
} else {
format!("{a}{x}{y}{z}{b}", x = 1, y = 1 + a + b - 10, z = a + b - 10)
};
use itertools::Itertools;
input.split(&src).join(&dst)
}
fn main() {
assert_eq!(f("123456789", 3, 4), "1237456789");
assert_eq!(f("123456789", 6, 7), "123456143789");
assert_eq!(f("3141592653589793238462643383279502884197169399375105820974944", 9, 7),
"3141592653589176793238462643383279502884191767169399375105820917674944");
}
>>561 Rust
fn second_smallest<T: Copy + Ord>(input: &[T]) -> Option<T> {
use std::cmp::Ordering::{Equal, Greater, Less};
input
.iter()
.copied()
.fold(None, |state, t| match state {
Some((_t0, Some(t1))) if t >= t1 => state,
Some((t0, _)) => match Ord::cmp(&t, &t0) {
Less => Some((t, Some(t0))),
Equal => state,
Greater => Some((t0, Some(t))),
},
None => Some((t, None)),
})
.and_then(|(_t0, t1option)| t1option)
}
fn main() {
assert_eq!(second_smallest(&[4, 5, 1, 7, 1, 2, 8, 9, 2, 7, 1]), Some(2));
assert_eq!(second_smallest(&[1, 1, 1]), None);
assert_eq!(second_smallest(&[] as &[i32]), None);
}
わからないのはどのへんなんだろう?
・型がジェネリックになっている点
・代入文がないなど関数型プログラミングになっている点
・パターンマッチングが使われている点
いずれも最近は対応している言語が増えてるような
可読性の良さから高階関数を使ったメソッドチェーンが一般的になってきたね
マイクロソフトがC#などでLINQ広めたのがきっかけで各言語もその有用性から導入するようになった
お題:ランダムな英文字列が与えられる。隣り合う英文字が同じ大文字だった場合、その間にその大文字の小文字を挿入せよ
In < abcDDefGG
Out > abcDdDefGgG
>>608 ruby
while 1
s=DATA.gets.chomp
exit if s==""
t=s.gsub(%r|([A-Z])\1|){$1+$1.downcase+$1}
puts "IN < #{s}\nOUT > #{t}"
end
__END__
abcDDefGG
>>606 正規表現みたい非人間的な書式はやめようぜっての
>>608
PowerShell
function f($s)
{
-join $(
foreach ($i in 0..($s.length - 2)) {
$s[$i]
if ($s[$i] -ne $s[$i + 1]) {continue}
if ($s[$i] -lt [char]"A" -or $s[$i] -gt [char]"Z") {continue}
([string]$s[$i]).ToLower()
}
$s[$i + 1]
)
}
"abcDDefGG", "abcDDDfGG" |% {"$_ → $(f $_)"}
[実行結果]
abcDDefGG → abcDdDefGgG
abcDDDfGG → abcDdDdDfGgG >>608 Rust
fn f(input: &str) -> String {
let mut output = String::new();
let mut pre_uppercase = None;
for char in input.chars() {
if Some(char) == pre_uppercase {
output.push(char.to_ascii_lowercase());
}
output.push(char);
pre_uppercase = char.is_ascii_uppercase().then_some(char);
}
output
}
fn main() {
assert_eq!(f("abcDDefGG"), "abcDdDefGgG");
assert_eq!(f("abcDDDfGG"), "abcDdDdDfGgG");
} >>608 Perl5、肯定先読みと置換の小文字変換
s/([A-Z])(?=\1)/\1\l\1/g, print for <DATA>;
__DATA__
abcDDefGG
abcDDDefGGG
実行結果
C:\Home>perl 22_608_ins_l.pl
abcDdDefGgG
abcDdDdDefGgGgG
>>611
お断り〜します〜♪
ハハ
(゚ω゚)
((⊂ノ ノつ))
(_⌒ヽ
εニ≡ )ノ`J >>608 java
https://ideone.com/YfufZz >>616 _人人人人人人人人人人人人_
> 置換の小文字変換!? <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄
勉強になりました
>>612は文字列長が1文字の場合にバクがあった。PowerShellの0..-1は空(から)ではなく0, -1になるのが
原因 (Rの0:-1も同様)。修正するには、fの最初に if ($s.length -lt 2) {return $s} を挿入する。
>>561 C++
https://ideone.com/bQBKIM C#のヌル許容型と同じ挙動のnullable型を自作し、
>>593のC#のmin2関数をジェネリック化、
ポインタ参照化して移植した。
https://ideone.com/p2LNC9 593のC++のmin2関数と実行速度を比較する¹と30%ほど遅い。文字列型や可変長数値型と
違って最大値が存在する固定長数値型では、それを利用するf593の方が良い。
──
¹ Microsoft C++では100回繰り返しテストが最適化され1回しか実行されない
>>621 最大値をundefined代わりに使ってはいけないと指摘があったのにまだ使っているのかいな
そのコードで入力数列がこうだった場合
vector<int> a = {IntMax - 1, IntMax};
2番目に小さい数として正解のintMaxを返さなければならない
>>622 >>593のC++プログラムの実行結果を参照。入力数列にINT_MAXが含まれる場合でも問題ない。
>>623 それはm1とm2を間接にポインタで持つために遅くなっているf593()
m1とm2を直接に整数で持つため速いf3()はIntMaxに対応できていない
>>624 >>621の速度比較テストに
>>570のf3も追加
https://ideone.com/scnfdu ポインタで持つf593との比で、整数で持つf570は6%速いだけ。一方、null許容型のf621は29%も遅い。
最大値が存在する型ではそれを利用する方が良いという結論に変わりはない。
まあ、同じ値の要素が大量に存在する入力データではf570は遅くなるが、平均的な速度はf570の方が速い。
f593でローカル変数へのポインタを返し得るのは如何かと
>>625 まずnullableのコードがおかしい
例えばoverload(op)のこれ
if (y.isNull) return false; \
return x op y.value; \
Nullだとfals eとなり
opの計算結果次第でもfal seとなり
両者を区別できない
>>625 あとvector扱うコードは倫理的に際どいかな
長さ0でないことを調べずに
いきなりint *m1 = &a[0], m2 = &y;
今回は長さ0の時に*m1をアクセスしないから論理的にギリセーフだけど際どい
そのへんのトリッキーさも含めて
(もしあれば)最小値も返す場合
(もしあれば)3番目の最小値も返す場合など
このIntMax方式は破綻すると思う
>>630 >>621に書いた通り、C#のヌル許容型T? (Nullable<T>のエイリアス) の挙動に従っただけだから。
文句があるならMicrosoftに言ってくれ。
いるよねえ他人の回答に文句だけつけて自分では回答しないやつ
他人の回答が間違いとなるようにお題を解釈するのは知的なことではないよバカの所業だよ
そんなことより
>>616のワンライナーがカッコよくてほれぼれする
コンパイラ警告無視するのが知的な事だと思ってそうだな
お題:ランダムな数列が与えられる。隣り合う数字が偶数同士の時、あいだに0を。奇数同士の時は1を挿入し、それ以外は何も挿入しない
In < 123346
Out > 12313406
>>640 ruby
DATA.readlines(chomp:1).map{|e|
a=e.split("").map{|f| f.to_i}
(0..a.size-2).each{|n|
a[n]=a[n]*10 if (a[n]%2==0 && a[n+1]%2==0)
a[n+1]=a[n+1]+10 if (a[n]%2==1 && a[n+1]%2==1)}
puts "IN < #{e}\nOUT > #{a.map{|f| f.to_s}.join}"}
__END__
123346
>>640
PowerShell (一般的な文字コードを想定)
function f([string]$s)
{
$rprev = 2
-join ([char[]]$s |% {
$r = $_ % 2
if ($r -eq $rprev) {$r}
$rprev = $r
$_
})
}
123346, 12333468, 1, "" |% {"$_ → $(f $_)"}
[実行結果]
123346 → 12313406
12333468 → 123131340608
1 → 1
→ 正規表現置換なら、
function f($s)
{
$s -replace "[02468](?=[02468])", "$&0" -replace "[13579](?=[13579])", "$&1"
}
1回で済ますなら、
function f($s)
{
[RegEx]::Replace($s, "[02468](?=[02468])|[13579](?=[13579])", {$_ = $args[0].value[0]; "$_$($_ % 2)"})
}
>>640 Rust
fn f(input: &[u8]) -> Vec<u8> {
input.windows(2).fold(Vec::new(), |mut vec, w| {
if vec.is_empty() {
vec.push(w[0]);
}
if (w[0] ^ w[1]) & 1 == 0 {
vec.push(w[0] & 1 + b'0');
}
vec.push(w[1]);
vec
})
}
fn main() {
assert_eq!(f(b"123346"), b"12313406");
assert_eq!(f(b"12333468"), b"123131340608");
} Vecのnewやpushなど普通にcollectに任せる手もあるね
条件付き挿入は汎用にOptionで取捨を示してflat_mapとflattenでも可能
前値など状態を保ちつつ1つにまとめるならfoldでイテレータに流すならscan
一例としてこんな感じ
fn f(input: &[u8]) -> Vec<u8> {
input
.iter()
.scan(None, |pre, &x| {
Some([
pre.replace(x & 1)
.and_then(|p| (p == x & 1).then_some(p + b'0')),
Some(x),
])
})
.flat_map(|list| list.into_iter().flatten())
.collect()
}
>>640
Rust >>640 >>643-644の3つのfを上から順にf1, f2, f3とし、長い文字列を引数として呼び出したときの
実行時間を比較すると、
$s = -join (1..10000)
$t = 1..3 |% {(iex "measure-command {f$_ $s}").ticks}
$tmin = ($t | measure -min).minimum
1..3 |% {"f$_`: {0:0.00}倍" -f ($t[$_ - 1] / $tmin)}
[実行結果の一例]
f1: 34.78倍
f2: 1.00倍
f3: 14.93倍
大差でf2 < f3 < f1となった。インタプリタ言語のコード実行は遅いので、処理を自分で
書くほど遅くなり、ライブラリ関数等に丸投げすれば速くなることによる。
https://ideone.com/GVewWL コンパイラ言語のC#で同様の比較をすると (PowerShellより速いので文字列を長くし、
f1の改良版としてStringBuilder使用のf4を追加した)、当然f4< f1 < f2 < f3になった。
>>647
関数型でタブーの可変な変数宣言してもよいなら、もっと簡単になるね。
fn f(input: &[u8]) -> Vec<u8> {
let mut pre = None;
input
.iter()
.flat_map(|&x| {
[
pre.replace(x & 1)
.and_then(|p| (p == x & 1).then_some(p + b'0')),
Some(x),
]
.into_iter()
.flatten()
})
.collect()
} mutableの使用は必要最小限が望ましいが
mutableを使えない言語は実用的ではない
>>608 >>651とかとアルゴリズムはほぼ同じ。これといった捻りはない。
よく分からないが5chに書き込みがブロックされたのでURLのコロンまでは削った。
Perl
//paiza.io/projects/zAqms-VVEWIMhcgr8AV6Pw
Kotlin
//paiza.io/projects/iu8mTSyKsxqWx_T51Wpj4Q
C
//paiza.io/projects/bDkj3tRF_KmiBL67miRxyA
お題: Python の int.bit_count()
65535 → 16
15 → 4
6 → 2
1 → 1
0 → 0
-1 → 1
-6 → 2
-15 → 4
-65535 → 16
>>656 Rust
fn bit_count(x: i64) -> usize {
const MAGIC_1: u64 = 0x5555555555555555; // 0101..0101
const MAGIC_2: u64 = 0x3333333333333333; // 0011..0011
const MAGIC_3: u64 = 0x0f0f0f0f0f0f0f0f;
const MAGIC_4: u64 = 0x00ff00ff00ff00ff;
const MAGIC_5: u64 = 0x0000ffff0000ffff;
const MAGIC_6: u64 = 0x00000000ffffffff;
let x = x.unsigned_abs();
let x = (x & MAGIC_1) + ((x >> 1) & MAGIC_1);
let x = (x & MAGIC_2) + ((x >> 2) & MAGIC_2);
let x = (x & MAGIC_3) + ((x >> 4) & MAGIC_3);
let x = (x & MAGIC_4) + ((x >> 8) & MAGIC_4);
let x = (x & MAGIC_5) + ((x >> 16) & MAGIC_5);
let x = (x & MAGIC_6) + ((x >> 32) & MAGIC_6);
x as usize
}
fn main() {
assert_eq!(bit_count(65535), 16);
assert_eq!(bit_count(15), 4);
assert_eq!(bit_count(6), 2);
assert_eq!(bit_count(1), 1);
assert_eq!(bit_count(0), 0);
assert_eq!(bit_count(-1), 1);
assert_eq!(bit_count(-6), 2);
assert_eq!(bit_count(-15), 4);
assert_eq!(bit_count(-65535), 16);
}
>>656 Rust
trait BitCount {
fn bit_count(&self) -> usize;
}
impl BitCount for i32 {
fn bit_count(&self) -> usize {
self.unsigned_abs().count_ones() as usize
}
}
use num::{BigInt, One};
impl BitCount for BigInt {
fn bit_count(&self) -> usize {
self.iter_u64_digits().map(|x| x.count_ones() as usize).sum()
}
}
fn main() {
for (input, output) in [(65535, 16), (15, 4), (6, 2), (1, 1), (0, 0), (-1, 1), (-6, 2), (-15, 4), (-65535, 16)] {
assert_eq!(input.bit_count(), output);
}
assert_eq!(BigInt::from(-1).bit_count(), 1);
assert_eq!((BigInt::from(2).pow(1_000_000_000) - BigInt::one()).bit_count(), 1_000_000_000);
} intは処理単位のことなんだけどな
何ビットで表現できるかという意味ではない
負の場合に表現可能なビット数を配慮しないとPython の int.bit_count()と同じ結果にならないんジャマイカじゃまいか
たぶんPythonの整数がbigintのせいだとおもう
絶対値とってpopcountとかやらないと意外とあれこれ書いてプチ長めのコードになりそうなおかん
よく見たらみんな絶対値をとったりbigintを使ったりしてるな
>>656
PowerShellのBigIntなら、
$b = @(0)
1..8 |% {$b += $b |% {$_ + 1}}
function bit_count([BigInt]$n)
{
($b[[BigInt]::Abs($n).ToByteArray()] | measure -sum).Sum
}
65535, 15, 6, 1, 0, -1, -6, -15, -65535, [BigInt]::Pow(123, 45) |% {
"$_ → $(bit_count $_)"
}
[実行結果]
65535 → 16
15 → 4
6 → 2
1 → 1
0 → 0
-1 → 1
-6 → 2
-15 → 4
-65535 → 16
11110408185131956285910790587176451918559153212268021823629073199866111001242743283966127048043 → 159 お題:1からnまでの自然数のビット単位での総排他的論理和1 ⊕ 2 ⊕ 3 ⊕ … ⊕ nを求める
関数を作り、n = 123456789, 12345678901234567890のときの値を表示せよ。
>> 664 Rust
fn f(n: u64) -> u64 {
// f(n) = 1⊕2⊕3⊕...⊕n とすると (2k)⊕(2k+1)=1 であるから 1⊕1=0 より
// f(4k+1) = (4k+1)⊕(4k)⊕(4k-1)⊕(4k-2)⊕f(4k-3) = f(4(k-1)+1) = ... = f(1) = 1
// f(4k+3) = (4k+3)⊕(4k+2)⊕f(4k+1) = 0
// f(4k) = (4k)⊕f(4k-1) = 4k
// f(4k+2) = (4k+2)⊕f(4k+1) = (4k+2)⊕1 = 4k+3
match n % 4 {
0 => n,
1 => 1,
2 => n + 1,
3 => 0,
_ => unreachable!(),
}
}
fn main() {
for n in [123456789, 12345678901234567890] {
println!("f({n}) = {fn}", fn = f(n));
}
}
出力
f(123456789) = 1
f(12345678901234567890) = 12345678901234567891
>>656
PowerShellでもPopCountがいつの間にか使えるようになっていた。Version 7.5.0で動作確認。
function bit_count($n)
{
[BigInt]::PopCount([BigInt]::Abs($n))
}
65535, 15, 6, 1, 0, -1, -6, -15, -65535, [BigInt]::Pow(123, 45) |% {
"$_ → $(bit_count $_)"
}
実行結果は>>663と同じ。 お題:数列が入力される。元の数列に逆順にした数列を減算したときの値を出力せよ
In < 12345
OUt > -41976 (12345 - 54321)
>>670
PowerShell
function f([BigInt]$n)
{
$c = [char[]][string]$n
$n - [BigInt]-join $c[-1..-$c.length]
}
12345, [BigInt]::Pow(12, 34) |% {"$_ → $(f $_)"}
[実行結果]
12345 → -41976
4922235242952026704037113243122008064 → 314233029528909439273950854852378624 >>671 12の34乗は合っているけどその後の差がおかしくない?
4922235242952026704037113243122008064 から
4608002213423117304076202592425322294 を引いて
314233029528909399960910650696685770 が正解のところ
314233029528909439273950854852378624 となっているよ
正解は1の位が「4 - 4 = 0」になるはずだよね
>>670 Rust 逆文字列を生成する版
use num::BigInt;
fn odai(input: &str) -> Option<String> {
let rev_input: String = input.chars().rev().collect();
let x: BigInt = input.parse().ok()?;
let y: BigInt = rev_input.parse().ok()?;
Some((x - y).to_string())
}
fn main() {
assert_eq!(odai("12345"), Some("-41976".to_string()));
assert_eq!(odai("4922235242952026704037113243122008064"), Some("314233029528909399960910650696685770".to_string()));
}
>>670 Rust 逆文字列を生成しない&整数ジェネリック版
use num::{BigInt, CheckedAdd, CheckedMul, CheckedSub, FromPrimitive};
fn chars_to_integer<X>(input: impl Iterator<Item = char>) -> Option<X>
where X: FromPrimitive + CheckedMul + CheckedAdd,
{
let (zero, ten) = (X::from_u32(0).unwrap(), X::from_u32(10).unwrap());
input
.map(|c| X::from_u32(c.to_digit(10)?))
.try_fold(zero, |acc, x| acc.checked_mul(&ten)?.checked_add(&x?))
}
fn odai<X>(input: &str) -> Option<X>
where X: FromPrimitive + CheckedMul + CheckedAdd + CheckedSub,
{
let x = chars_to_integer::<X>(input.chars())?;
let y = chars_to_integer::<X>(input.chars().rev())?;
x.checked_sub(&y)
}
fn main() {
assert_eq!(odai::<i64>("12345"), Some(-41976));
assert_eq!(odai::<BigInt>("4922235242952026704037113243122008064"), Some("314233029528909399960910650696685770".parse::<BigInt>().unwrap()));
} >>672 確かに間違っていた。PowerShellの旧ヴァージョンでは [BigInt]文字列 と書くだけで
文字列をBigInt型に正確に変換できるから
>>671のプログラムでも正しい結果が得られるが、
新ヴァージョンではdouble経由での変換に仕様変更されたようで誤差が生じてしまうから
[BigInt]::Parse(文字列) と書かなければならなくなった。
数列の長さは指定されていない。
10 INPUT "0-9";I
20 PRINT "0"
30 END
>>673 これらのwhere~は何という名称ですか?
> where X: FromPrimitive + CheckedMul + CheckedAdd,
> where X: FromPrimitive + CheckedMul + CheckedAdd + CheckedSub,
>>670 Perl5
use bigint;
print $_ - reverse($_), "\n" for 12345, 4922235242952026704037113243122008064;
実行結果
$ perl 22_670_reverse_minus_biginit.pl
-41976
314233029528909399960910650696685770
>>670
PowerShellでジェネリック化(もどき?)
途中式や結果が入力値の型で表せない場合は$nullを返す。
function f($n)
{
$T = $n.GetType()
$s = [string]$n
try {
$n - $T::Parse(-join $s[-1..-$s.Length]) -as $T
} catch {
$null
}
}
12345, [BigInt]::Pow(12, 34), [byte]12, [sbyte]12, [sbyte]123, -123 |% {
"[$($_.GetType())]$_ → $(f $_)"
}
-- 実行結果 --
[int]12345 → -41976
[bigint]4922235242952026704037113243122008064 → 314233029528909399960910650696685770
[byte]12 →
[sbyte]12 → -9
[sbyte]123 →
[int]-123 → お題:36桁以下の負でない整数で16進表記が10進表記の部分文字列であるものをすべて求めて下さい。
(例)
・1の16進表記1は10進表記1の部分文字列です
・123の16進表記7Bは10進表記123の部分文字列ではありません
・357440の16進表記57440は10進表記357440の部分文字列です
※遅い言語では15桁以下で解いても構いません
>>676 where句だよ
型Xのトレイト境界を宣言してる
>>680 Perl5、ナイーブな処理方式だと時間がかかり過ぎで最後まで解けないおそれがあるが、なかなかほかに回答者が現れないし、
出現傾向を見るだけでも…と思って、16進数の桁にa-fの現れる値をskipするナイーブな処理方法で。
$m = sprintf '%x', 9 x 15; # 10進で15桁まで
print $m . ' '. hex($m)."\n";
$m =~ s/[a-f]/9/g;
print "1 .. 0x$m\n";
print "".localtime."\n";
for (1 .. $m) {
$d = hex($_);
if (0 <= index($d, $_)) {
$n++;
print "$d, 0x$_\n";
}
}
print "".localtime."\n";
print "$n count found"; >>682
実行結果 (改行数を減らすため適度につなげてます)
$ perl 22_680_hex_substr_1.pl
38d7ea4c67fff 999999999999999
1 .. 0x3897994967999
Tue Mar 18 09:15:31 2025
1, 0x1 2, 0x2 3, 0x3 4, 0x4 5, 0x5 6, 0x6 7, 0x7 8, 0x8 9, 0x9
357440, 0x57440 357441, 0x57441 357442, 0x57442 357443, 0x57443 357444, 0x57444
357445, 0x57445 357446, 0x57446 357447, 0x57447 357448, 0x57448 357449, 0x57449
1079653, 0x107965 1081713, 0x108171 1122966, 0x112296 1123079, 0x112307 1123080, 0x112308
2246166, 0x224616 3369253, 0x336925 3371313, 0x337131 3412566, 0x341256
4494393, 0x449439 4494400, 0x449440 4535653, 0x453565
5658739, 0x565873 5658740, 0x565874 5660793, 0x566079 5660800, 0x566080 5702166, 0x570216
6783879, 0x678387 6783880, 0x678388 6784000, 0x678400
6825253, 0x682525 7948339, 0x794833 7948340, 0x794834 7950393, 0x795039 7950400, 0x795040
2182104640, 0x82104640 2182104641, 0x82104641 2182104642, 0x82104642 2182104643, 0x82104643 2182104644, 0x82104644
2182104645, 0x82104645 2182104646, 0x82104646 2182104647, 0x82104647 2182104648, 0x82104648 2182104649, 0x82104649
1263629042727, 0x12636290427 1307655353654, 0x13076553536 2573583194436, 0x25735831944 2617616245848, 0x26176162458
3330782168640, 0x30782168640 3330782168641, 0x30782168641 3330782168642, 0x30782168642 3330782168643, 0x30782168643
3330782168644, 0x30782168644 3330782168645, 0x30782168645 3330782168646, 0x30782168646 3330782168647, 0x30782168647
3330782168648, 0x30782168648 3330782168649, 0x30782168649 3883544086630, 0x38835440866 3927569962533, 0x39275699625
3927570397557, 0x39275703975
Core i7-8559U で6時間ほど実行してここまで高々13桁。
やはり想定通り気の利いた高速解放が要りますテヘペロ。 >>680 ruby
(0..10**16-1).each{|e| puts "#{e},0x#{e.to_s(16)}" if %r|[a-f]|!~e.to_s(16)}
>>683 14桁と15桁には該当値がないので、そこに列挙された数に0を追加した72個が15桁以下の答で
結果的には合っているよ。
出題時に作ったC++プログラムはideoneで36桁以下を0.43秒で完了した。これをPowerShellに
移植したプログラムは15桁以下を0.5秒未満、36桁以下を数分で完了した。
その後、改良したC++プログラムではideoneで36桁以下を0.23秒に短縮できた。
>>683 >やはり想定通り気の利いた高速解放が要りますテヘペロ。
そのヒントになるかいな…?
・16進数を10進数に変換すると桁数は同じまたは高々1桁増えるのみ(だともう、証明略)
・桁数が同じ場合、16進数と10進数が同じということはあり得ない、自明
・一桁増える場合は先頭または末尾に一桁増える。残りが16進数と同じ部分文字列であるかが評価対象となる
>>685 あそうなんだ。じゃオレ様が一番乗りということでヨロ
ノシ
>>686 >・一桁増える場合は先頭または末尾に一桁増える。残りが16進数と同じ部分文字列であるかが評価対象となる
二桁増える場合があるのでこれは誤りでした
ようやく題意は理解したけど良い解法が思いつかない
ちなみに36桁以下だと答えはいくつありますか?
>>680 ruby 遅いけど
i=0
while i<10**16
if %r|[a-f]|=~i.to_s(16)
i=i.to_s(16).gsub(%r|[a-f].*|){|e| e.gsub(%r|.|,"f")}.hex
else
puts "#{i},0x#{i.to_s(16)}" if %r|#{i.to_s(16)}|=~i.to_s
end
i+=1
end
>>686 > ・桁数が同じ場合、16進数と10進数が同じということはあり得ない、自明
大間違い。16進数と10進数で桁数が同じ値のうち、一桁のものは、16進も10審も同じだった…orz
結局、高速解放はあるんだろうか?
あるいはコラッツ予想みたいに「無いかもしれない」類の、考えるだけ無駄な問題なのだろうか?
>>689 167個で最大値は697786638998562641695629924526065234
>>691 時間をかけて64桁以下で解いたら、405個で最大値は
2714476666993915057605587441263923823484611431446449961712093492
だった。これはナイーヴな解法ではC++ですら到底求められない値だから、高速解法が
実在する証になっているだろう。
解答例は1週間くらい経ったら載せるので、それまでよく考えてみて下さい。
お題:単位分数のエジプト風分解(2進数風味)
1/aを、1/a=1/b+c/dを満たす1/bとc/dに分解する。
aは1以上の整数とする。
c, dは整数とし、bは2の整べき乗(1, 2, 4,...)とする。
c/dは絶対値が最小である事(負数であってもよい)。
例:
1/3→1/4+1/12 : b=4, c=1, d=12
1/7→1/8+1/56 : b=8, c=1, d=56
1/9→1/8-1/72 : b=8, c=-1, d=72(c=1, d=-72も可)
1/13→1/16+3/208 : b=16, c=3, d=288
1/60→1/64+1/960 : b=64, c=1, d=960
>>693 R
https://ideone.com/TaaAw2 aが2の整べき乗の場合の出力形式に指定がなかったので適当に決めた。
>>693 Rust
fn f(a: i64) -> String {
let b = (a as u64).next_power_of_two() as i64;
let b = if 3 * a > 2 * b { b } else { b >> 1 };
let (c, d) = (b - a, a * b);
let shift = c.trailing_zeros().min(d.trailing_zeros());
let (c, d) = (c >> shift, d >> shift);
if a == b {
format!("1/{a}=1/{b}")
} else {
format!("1/{a}=1/{b}{c:+}/{d}")
}
}
fn main() {
assert_eq!("1/3=1/4+1/12", f(3));
assert_eq!("1/7=1/8+1/56", f(7));
assert_eq!("1/9=1/8-1/72", f(9));
assert_eq!("1/13=1/16+3/208", f(13));
assert_eq!("1/60=1/64+1/960", f(60));
assert_eq!("1/64=1/64", f(64));
assert_eq!("1/6718464=1/8388608+1631/55037657088", f(6718464));
assert_eq!("1/123456789=1/134217728+10760939/16570089725755392", f(123456789));
} >>680 Rust
fn odai_680() -> Vec<i128> {
let mut answer = vec![0];
let n_max = (0..).find(|&n| pow16(n + 1) > pow10(36)).unwrap();
for s in (0..).take_while(|&s| pow16(n_max) >= pow10(n_max + s + 1)) {
let c = (0..=n_max).map(|i| pow16(i) - pow10(i + s)).collect::<Vec<_>>();
let rmax = c.iter().scan(0, |s, &c| { *s += if c > 0 { c * 9 } else { 0 }; Some(*s) }).collect::<Vec<_>>();
let rmin = c.iter().scan(0, |s, &c| { *s += if c < 0 { c * 9 } else { 0 }; Some(*s) }).collect::<Vec<_>>();
let (mut i, mut n, mut d, mut ct) = (0, 1, vec![0; c.len()], vec![0; c.len() + 1]);
loop {
d[i] += 1;
if d[i] < 10 {
let m = pow10(n as u32 + s); ct[i] = c[i] * d[i] + ct[i+1];
if i == 0 {
if ct[0] >= 0 && ct[0] % m < pow10(s) { answer.push(d.iter().take(n).rev().fold(0, |sum, &d| sum * 16 + d)) }
} else {
let (max, min) = (ct[i] + rmax[i-1], ct[i] + rmin[i-1]);
if max >= 0 && (max - min > m || pow10(s) > min % m || min % m > max % m) { i -= 1; }
}
} else { d[i] = -1; i += 1; if i == n { if n == d.len() { break; } n += 1; } }
}
}
answer.sort(); answer
} >>697
// 略記
fn pow16(x: u32) -> i128 { 16_i128.pow(x) }
fn pow10(x: u32) -> i128 { 10_i128.pow(x) }
// 結果検証
fn main() {
let answer = odai_680();
assert_eq!(167, answer.len());
for &a in &answer {
assert!(a.to_string().contains(&format!("{a:x}")));
}
assert_eq!(0, answer[0]);
assert_eq!(1, answer[1]);
assert_eq!(357440, answer[10]);
assert_eq!(2182104649, answer[54]);
assert_eq!(3927570397557, answer[71]);
assert_eq!(38135630558262267902210, answer[99]);
assert_eq!(331052794565713975838768757043267, answer[152]);
assert_eq!(697786638998562641695629924526065234, answer[answer.len() - 1]);
} >>697-698 Rustはよく知らないが、mainのforループ内をprintln!("{}", a);に置き換えれば解が表示されるんだよね?
実行結果を
>>685で述べたC++プログラムのものと照合したら167個の解すべてが一致した。見事正解!
実行時間はC++プログラムの数倍かかるようだが、ideoneでの実行時間も見たいので載せて下さい。
>>680から1週間経ったので解答例を掲載
>>685を書いたときに作ってあった2つのC++プログラム
https://ideone.com/KID2jR https://ideone.com/ysdd6b 1番目ではsolve関数の再帰呼び出しの対象とするx[p]の下限と上限を線形探索するが、
2番目では二分探索する。要素数10では二分探索の効果は薄いと思いきや、大分速くなった。
2番目を読み返していたらバグを発見してしまった。i = N - 1のとき63行目のa[i + 1]はa[N]となり
配列の添字範囲外アクセス。0との比較だけだし、if文の評価がどっちでも以降の処理は結局同じだから、
実害も解への影響もないが、厳格さが必要ならif ((i + 1 < N ? a[i + 1] : 0) >= 0) {と書き換えるべきだな。
実行時間への影響は無視できる。
それぞれのPowerShellへの移植版
https://ideone.com/vEGZ3D https://ideone.com/azzMa4 完全な逐語訳ではなく、PowerShellで書くと遅くなったり煩雑になったりする箇所は適宜改変した。
15桁以下の場合は64ビット整数でも桁溢れしないので、BigIntの代わりにInt64を使えば少し速くなる。
非素数であることが既知の巨大整数を素因数分解するときの
最速のアルゴリズムって何がある?
>>699 > 実行時間はC++プログラムの数倍かかるようだが
rustc -C opt-level=2 でコンパイルしたら
g++ -O2 でコンパイルした ideone_KID2jR.cpp (
>>700の一つめ) とほぼ同じ速度出たよ
>>702 データ精度を揃えたアルゴリズム比較のために
>>697-698をi128固定ではなくnum::BigIntにして計測して見ては?
あと出題者
>>685は
>>700の二つ目で(倍速以上に)短縮出来たと言っているよ
そこまでは興味ないや
「数倍」だったのはもしかして最適化オプション付けてなかったんじゃない?ってだけの話
>>697-698をBigIntに変えるのはどうしたらいいのか分かんなかったので
>>700の方を boost::multiprecision::cpp_int から boost::multiprecision::int128_t に変えてみた
改変版 | オリジナル
https://ideone.com/Ie0HhO 0.12s |
https://ideone.com/KID2jR 0.43s
https://ideone.com/np3p5h 0.11s |
https://ideone.com/ysdd6b 0.23s
>>705 感心した、出題者回答C++コードはほんの少し変更するだけで簡単にBigInt/i128切り替え出来るのか
>>697-698 Rustはどうなのかな?
>>704 >>699では最適化オプションを付けてrustc -O a.rsでコンパイルした。最適化なしでは
ありの4.6倍くらい掛かった。もしやと思ってコンパイラをアップデートしてみたら、
実行時間は約3分の1に激減し、
>>700の1番目と大差ない1.3倍ほどに収まった。
Rustの古いコンパイラ(5年前のもの)がこんなに低性能だったとは…
c言語で実用的なプログラムを作りたい。
いいテーマはありますか?
お題:#(シャープ)を入力の段数でウンコ状に並べて出力せよ
出力は全角でも半角でもどちらでもよしとする(5ch は半角スペース表示できない)
in < 3
out >
#
###
#####
>>710
PowerShell
function unko($n)
{
if ($n -ge 1) {1..$n |% {" " * ($n - $_) + "#" * (2 * $_ - 1)}}
}
unko 3
-- 実行結果 --
#
###
##### お題:素因数の総和が2025である2000万以下の自然数をすべて求めて下さい。
例)
32272
素因数分解すると32272 = 2 × 2 × 2 × 2 × 2017で、
素因数の総和は2 + 2 + 2 + 2 + 2017 = 2025となります。
※20億以下でもC++で5秒以内に余裕で完了できますが、出力が長すぎるため2000万以下としました。
その結果、Rでも5秒以内に余裕で完了できる問題になりました。
>>710 山状ではだめだったのか
俺にはわからない
お題
AさんがBさんに惚れてることを
A-B
と表します
両思いのペアを出力してください
入力
D-L,U-X,U-Y,U-R,Z-B,B-E,B-M,B-N,V-H,V-X,W-F,W-R,R-B,R-W,O-W,O-S,F-A,Q-X,P-E,P-L,X-X,Y-M,Y-C,L-U,L-V,I-X,E-B,H-M,A-S
出力
B,E
R,W
>>714
PowerShell
$s = "D-L,U-X,U-Y,U-R,Z-B,B-E,B-M,B-N,V-H,V-X,W-F,W-R,R-B,R-W,O-W,O-S,F-A,Q-X,P-E,P-L,X-X,Y-M,Y-C,L-U,L-V,I-X,E-B,H-M,A-S"
$h = @{}
$s -split "," |% {
$a, $b = $_ -split "-"
$h[$a] += , $b
}
foreach ($a in $h.keys) {
foreach ($b in $h[$a]) {
if ($a -lt $b -and $h[$b] -contains $a) {"$a,$b"}
}
}
-- 実行結果 --
B,E
R,W >>714
PowerShellでもう少し短く
$s = "D-L,U-X,U-Y,U-R,Z-B,B-E,B-M,B-N,V-H,V-X,W-F,W-R,R-B,R-W,O-W,O-S,F-A,Q-X,P-E,P-L,X-X,Y-M,Y-C,L-U,L-V,I-X,E-B,H-M,A-S"
$h = @{}
$s -split "," |% {
$a, $b = $_ -split "-"
$i, $t = if ($a -lt $b) {1, "$a,$b"} else {2, "$b,$a"}
$h[$t] = $h[$t] -bor $i
}
$h.keys |? {$h[$_] -eq 3} | sort
-- 実行結果 --
B,E
R,W >>714
Rust
use itertools::Itertools;
fn f(input: &str) -> impl Iterator<Item = &str> {
input.split(',')
.map(|pair| (pair, pair.splitn(2, '-').collect_tuple().unwrap()))
.filter(|(_, (a, b))| a < b)
.flat_map(|(pair, (a, b))| {
input.split(',')
.map(|pair| pair.splitn(2, '-').collect_tuple().unwrap())
.filter_map(move |(x, y)| (a == y && b == x).then_some(pair))
})
}
fn main() {
let input = "D-L,U-X,U-Y,U-R,Z-B,B-E,B-M,B-N,V-H,V-X,W-F,W-R,R-B,R-W,O-W,O-S,F-A,Q-X,P-E,P-L,X-X,Y-M,Y-C,L-U,L-V,I-X,E-B,H-M,A-S";
itertools::assert_equal(["B-E", "R-W"], f(input).sorted());
} お題:1〜10までの範囲の乱数生成をn回行ったとき出た値の積が20の倍数になる確率Pnを出力せよ
n=2
2, 10 ... 20
4, 5 ... 20
Pn=???
n=3
2, 5, 2 ... 20
4, 5, 2 ... 40
Pn=???
>>718 ん?
何千回も試行してその実際の発生率を出すの?
それとも数学的に確率の理論値を出すの?
>>718 R Version4
https://ideone.com/r03zEZ ideoneのRは古すぎてエラーが出てしまうので、出力は入力欄に記載した。
巨大整数型を使わなければideoneでも実行できる。
https://ideone.com/K0RefY >>718 C++への移植版
https://ideone.com/g87ECX これもideoneのC++が古すぎて10行目をm = size(d)と書けず変更せざるを得なかった。
>>714 Kotlin
//paiza.io/projects/WMZL8ULLNxc0zJQPI2uUsA
URLあると書けなかったので先頭のhttps:を抜いた。
>>718 学校の課題をここに書くなって教わらなかったの?
>>718
>>721-722を整理して行列とヴェクトルの積ですっきり書けるようにした。
R (ideoneでも巨大整数型で実行可能になった)
https://ideone.com/sHNag3
C++
https://ideone.com/7zgflb
式を展開してしまえばPowerShellで結局これだけ。
$a, $b, $c, $d, $e, $f = 0, 1, 1, 2, 2, [BigInt]4
2..100 |% {
$a = 10 * $a + 5 * $b + 2 * $c + 2 * $d + $e
$b = 5 * $b + 3 * $c + $e + $f
$c = 5 * $c + $f
$d = 8 * $d + 4 * $e + 2 * $f
$e = 4 * $e + 2 * $f
$f = 4 * $f
for ($p = $a; $p % 10 -eq 0; $p /= 10) {}
"P[$_] = 0.$p"
} 半角スペースの意味がわからない
そういうこだわりは古臭いよ
>>725 変数名がa、b、cの時点でプロじゃねえな
俺が言ってるのは5chのプロじゃねえなってことだから
数学は関係ない
>>726 >>725の全角空白のこと? 項の書き忘れや書き間違いがないか分かりやすくするため。余分な空白や長い変数名が
ディスク・メモリ空間やコンパイル・インタプリト時間を無駄に増やすと気にする方が古臭くない?
とはいえ、今でもインタプリタ言語のPowerShellでは変数名を長くすると顕著に遅くなる。例えば、
$t1 = measure-command {for ($i = 0; $i -lt 1000000; $i++) {}}
$t2 = measure-command {for ($AnExtraordinarilyLongVariableName = 0; $AnExtraordinarilyLongVariableName -lt 1000000; $AnExtraordinarilyLongVariableName++) {}}
$t2.Ticks / $t1.Ticks
をPowerShell Ver.7で実行すると1.56前後の値が表示される。奇妙なことに、かなり古いVer.2では1前後の値になる。
実時間ではVer.7の$t2とVer.2の$t2が同程度なので、Ver.7では短い変数名での最適化が施されているということか。
それはさておき、
>>712を解く人はいませんか?
>>734 ループは毎回、構文を解析しているわけじゃねえぞ?
>>719 このお題の場合は数学的に答えを出そうとするとプログラムを作る必要がなくなってしまわないか?
人が普通に数学的に考えて行くと答えが出てしまいそうな気がするんだが。
またはAIに聞いたらすぐ答えが出そうな感じが。
>>712 Rust
fn solve(n: usize, limit: usize) -> Vec<usize> {
let mut answer = Vec::new();
let mut pnt = generate_primes(n).iter().skip(1).rev().map(|&p| (p, 0, 0)).collect::<Vec<_>>();
let (mut ci, mut cn, mut ct) = (0, n, 1_usize);
'advance: loop {
pnt[ci..].iter_mut().for_each(|(_p, n, t)| (*n, *t) = (cn, ct));
if cn & 1 == 0 && ct.leading_zeros() >= (cn >> 1) as u32 {
ct <<= cn >> 1;
if ct <= limit { answer.push(ct as usize); }
}
for (i, (p, n, t)) in pnt.iter_mut().enumerate().rev() {
if *n < *p { continue; }
*n -= *p; *t *= *p;
if *t > limit { continue; }
if *n == 1 { continue; }
if *n == 0 { answer.push(*t as usize); continue; }
(ci, cn, ct) = (i, *n, *t);
continue 'advance;
};
break;
}
answer.sort(); answer
} >>738
素因数の総和が2025になる問題を可能な素数の組合せ総当りで挑戦してみました
20億以下で約0.4秒と規定時間以内に実行できました
実行時間 solve(2025, 20000000): 22.638309ms
実行時間 solve(2025, 2000000000): 418.607978ms
fn main() {
for (n, limit) in [(2025, 2000_0000), (2025, 20_0000_0000)] {
let start_time = std::time::Instant::now();
let answer = solve(n, limit);
let end_time = std::time::Instant::now();
println!("実行時間 solve({n}, {limit}): {:?}", end_time - start_time);
// 個数と最初と最後の検証
let (valid_len, valid_first, valid_last) = match (n, limit) {
(2025, 2000_0000) => (1265, 30255, 19970000),
(2025, 20_0000_0000) => (49942, 30255, 1999986740),
_ => (0, 0, 0),
};
assert_eq!(answer.len(), valid_len);
assert_eq!(*answer.first().unwrap(), valid_first);
assert_eq!(*answer.last().unwrap(), valid_last);
}
} >>738-739 出題時に作成した解答例
C++
https://ideone.com/y1YZlj R
https://ideone.com/zvqAsg と解の個数と最小値・最大値が一致するので正解だろう。
ローカルでコンパイルしようとしたら、
error[E0425]: cannot find function `generate_primes` in this scope
と表示されコンパイルできなかったので、実行時間の比較はできなかった。
>>741
すみません
素数の一覧を返すだけなので素数列挙でもライブラリ利用でも何でもいいのですが
例えばエラトステネスの篩ならこんな感じの関数で
// 素数の一覧を返す [2, 3, 5, 7, 11, ... , (最大max)]
fn generate_primes(max: usize) -> Vec<usize> {
// maxの平方根までの素数の倍数を篩にかければ全ての素数が見つかる
let limit = max.isqrt() + 1;
let mut is_prime = vec![true; max + 1];
is_prime[0] = false;
is_prime[1] = false;
// 偽初期値
let mut prime = 1;
// 次の素数を探す (前回の素数以降でtrueを探すと次の素数)
while let Some(pos) = is_prime[(prime + 1)..limit].iter().position(|bool| *bool) {
prime += pos + 1;
// この素数の倍数をfalseにする 【エラトステネスの篩】
is_prime[(prime << 1)..].iter_mut().step_by(prime).for_each(|bool| *bool = false);
}
// 素数一覧を返す (trueになるindex値が素数)
is_prime.iter().enumerate().filter_map(|(index, bool)| bool.then_some(index)).collect()
} >>738-739, 742と
>>741のC++を解の標準出力なしに変更したものの実行速度を比較したら、
前者の方が2000万以下では27%、20億以下では11%速かった。
前者はどっち?
アルゴリズムが違うのかちょっと見てみる
>>744 前者は
>>738-739, 742のRustプログラム。後者 (C++プログラム) はvectorへの要素追加回数が
多いので時間が掛かっていそう。
たしかにC++の20億だと数秒かかりますね
何がそんなに違うのかな
vectorのメモリは必要分を最初に確保すると速くならない?
vectorの最初のサイズの初期値は要素10個分だったはず。11個目が追加されたら20個確保して全要素コピーんsんてやってたら遅いよ
ベクタはC++もRustも他でもほぼ同じ仕様で埋まると倍の新たなエリアを確保してコピー
これは2^n個が埋まった時点でそれ以前の累積コピー個数は
最悪の1個スタートでも1+2+4+ ... + 2^(n-2)+2^(n-1) =2^n - 1個しかない
つまりO(1)とみなせるため問題になることは少ない
言語による詳細な差もC++とRustならほぼ無いと思われる
一方で今回の20億以内で素数和が2025になる数を求める問題
C++版がRust版より約10倍遅くなってる原因は
・pushしていくベクタがRust版は1個でC++版は2026個のベクタを利用
・pushしていく回数がRust版は解の個数と同じ49942回でC++版は134621081回
ワーキングメモリ使用量の差が効いてる
>>747
vector p[0]〜p[S]のサイズの最大値4499個(20億以下では88876個)分のメモリを
for (auto &v : p) v.reserve(4499);
で最初に割り付けておくと、>>743ではRustの方が2000万以下で27%、20億以下で11%速かったのが、
2000万以下では差が縮まりRustの方が14%速く、20億以下では逆転しRustの方が20%遅くなった。
サイズの最大値は実行前には分からないから、上記の改変はあくまでもvectorのサイズ拡張が実行時間に
及ぼす影響を見るためのテストで、解答として使うことはできないが。
vectorのサイズ拡張は、新しいメモリ割り付けとそこへの要素コピーに掛かる時間によってだけではなく、
要素の格納アドレスが変わることによるキャッシュ有効率の低下によっても、速度低下をもたらしそう。
>>746, 748
どっちがどれだけ速いかは実行環境に依存するとはいえ、C++が20億で数秒とかRustより約10倍遅いと
いうのはいくら何でも遅すぎておかしいと思う。解の標準出力をなしにするのを忘れていたり、Windowsで
コンパイル後の実行ファイルの実行時間をPowerShellでmeasure-command {a.exe}のように計測して
ウィルス・チェックに要した時間も含まれていたりしない? >>738 に手を加えて10倍速くしてみた
fn solve(n: usize, limit: usize) -> Vec<usize> {
let mut answer = Vec::new();
let mut pnt = generate_primes(n).windows(2).rev().map(|s| (s[1], s[0], 0, 0)).collect::<Vec<_>>();
let (mut ci, mut cn, mut ct) = (0, n, 1_usize);
'advance: loop {
pnt[ci..].iter_mut().for_each(|(_p, _q, n, t)| (*n, *t) = (cn, ct));
if cn & 1 == 0 && ct.leading_zeros() >= (cn >> 1) as u32 {
ct <<= cn >> 1; if ct <= limit { answer.push(ct); }
}
'back: for (i, (p, q, n, t)) in pnt.iter_mut().enumerate().rev() {
'again: loop {
if *n < *p { continue 'back; }
*n -= *p; *t *= *p;
if *n ==1 || *t > limit { continue 'back; }
if *n == 0 { answer.push(*t); continue 'back; }
if *q > 3 {
let mut tt = *t * (*n % *q);
for _ in 0..(*n / *q) { tt *= *q; if tt > limit { continue 'again; } }
}; break 'again;
}; (ci, cn, ct) = (i, *n, *t); continue 'advance;
}; break 'advance;
}; answer.sort(); answer
} すごいな
アルゴリズムの違いでそんなに速度差変わるものなんだな
>>750 これはとても速いな。ローカルで実行してみたら、
>>738のRustプログラムと比較して
2000万以下で16倍、20億以下で55倍の速さだった。
>>741のC++プログラムは for (int i = S; i >= 2; i--) のループの最後のi = 2の場合を
ループの外に出して最適化 (p[S]以外のp[_]への要素追加をしないように) するだけで、
20億以下で解の出力なしのときの実行時間が元のプログラムの半分未満になるな。
https://ideone.com/RtTEO2 (1.02秒)
↓
https://ideone.com/1O04wl (0.44秒)
>>754 それに気づいたけど
まだ
>>750と比べて20倍遅いからメモ化の方針が徒となってるのかな
>>756 遅い原因は長さ2000万のベクタ利用?
素因数和2025のお題の3系統のコードを読み解いてみた
>>756 2000万まで各々で素因数の和を求めて2025になるかを確認する方法。
ただし各数の素因数分解を工夫せずにすると大変なので、
各数の最小素因数(SPF)を先に一気にエラトステネスの篩で求めてる。
それを用いれば各数の素因数分解はその分解数回の割算だけで求まる。
ただしそのSPF表のために長さ2000万のベクタを用いている。
もし20億までなら32bit✕20億で8GBが許容できるとしても、
あるいはこのSPF一覧のベクタを用いなくても、
20億回の処理を劇的に減らす枝刈り方法を組み込めないと厳しい。
2000万までの計算でも一番遅い。
>>741 2000万個すべてを素因数分解する方法とは逆に、
2025以下の素数の組み合わせを調べていく方法。
そのうち和が2025になる組み合わせの積が各解となる。
それを効率よく求めるために2025(+1)個のベクタのベクタpを用意している。
つまり和がsumとなる時の積をp[sum]に記録していく。
効率面からの仮の初期値p[0]に1を入れて、各素数iについて降順に、
ベクタp[j]にxがある時、ベクタp[i+j]にx*iをpushしていく。
ここでjの上限は 2025 - i、処理するxの上限は 2000万 / i の枝刈りができる。
最終的にベクタp[2025]の一覧が解となる。
2025個のベクタを用いることが長所および短所になっている。
この改良版
>>754では、最後の素数2だけ特別扱いすることで倍速にしている。
>>738 これも2025以下の素数を組み合わせて和が2025になる解を調べる方法。
解一覧を収めるベクタ以外は、固定の長さ305のベクタのみが使われている。
この長さの 305 とは2025以下~3以上の素数[2017, 2011, ... 5, 3]の数になってる。
各素数の冪乗の和 2017^e2017 + 2011^e2011 + ... + 5^e5 + 3^e3 及び積を計算していくが、
各指数のe2017などは解に不要なので使われておらず、
各冪乗の和自体も不要なので2025までの残りの数が使われていて、
固定長ベクタの値は(素数, 残りの数, ここまでの積)の3つ組となっている。
その素数を1つ使うと残りの数が減算されてて積が乗算されるのを繰り返していく。
素数2だけ特別扱いされており、残りの数の半分だけ左シフトすると解の積が出来上がる。
各if~continueが枝刈りとなっていて、残りの下限(=和の上限)や積の上限などがある
この改良版
>>750では、次の素数以降の組み合わせで起き得る積の下限で枝刈りしている。
例えば7以下の素数で残り21ならば積の下限は7*7*7=343となるため、
ここまでの積に343を掛けた値が2000万(または20億)を超えていれば枝刈りできるようだ。
このアルゴリズムは作業メモリが固定で小さく常にL1キャッシュに乗り有利と思われる点と、
様々な枝刈りがしやすく処理する組み合わせを大きく減らしている点により、
他のアルゴリズムより桁違いに高速になっていると推測される。
お題:0か1のランダムな要素を持つW*Hの行列と二点の座標x, yとp, qが入力される
直線(x,y)→(p, q) を行列内で要素1に当たらないように任意の位置に合同変換したい
合同変換できる座標があればその二点の座標を出力し、なければ「なし」と出力せよ
行列の1は格子点上の印なのかクロスワードの黒マスなのか
(x,y)、(p,q)は任意の点なのか格子点なのか
合同変換される直線(x,y)→(p,q)は実は線分だったりしないのか
無限の可能性を感じさせるお題だな
検証用のデータを書いていないお題は失格
入力例とその時の出力例が必要
もし出力が複数個で長いならその特例の一部や個数など
お題
2次元の配列があったときに
一番左上を起点として右上方向、左下方向、右上方向…
というふうに斜めに配列の要素をたどることを
ジグザグスキャンと名付けます
たとえば、3 * 3の配列の場合は次の順番で配列の要素にアクセスします
(1, 2, 6)
(3, 5, 7)
(4, 8, 9)
二次元の配列を入力としてジグザグスキャンを行ってください
結果を1次元の配列として出力してください
例
入力: (A, B, C), (D, E, F), (G, H, I)
出力: (A, B, D, G, E, C, F, H, I)
入力: (A, B, C), (D, E, F)
出力: (A, B, D, E, C, F)
入力: (A, B), (C, D), (E, F)
出力: (A, B, C, E, D, F)
>>766
Rust
fn f<T: Clone, const M: usize, const N: usize>(input: &[[T; N]; M]) -> Vec<T> {
let mut output = Vec::<T>::new();
for x in 0..(M + N - 1) {
let start = if x < N { 0 } else { x + 1 - N };
let end = if x < M { x } else { M - 1 };
let iter = (start..=end).map(|m| input[m][x - m].clone());
if x & 1 == 1 {
output.extend(iter.clone());
} else {
output.extend(iter.rev());
}
}
output
}
fn main() {
assert_eq!(f(&[['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']]), ['A', 'B', 'D', 'G', 'E', 'C', 'F', 'H', 'I']);
assert_eq!(f(&[['A', 'B', 'C'], ['D', 'E', 'F']]), ['A', 'B', 'D', 'E', 'C', 'F']);
assert_eq!(f(&[['A', 'B'], ['C', 'D'], ['E', 'F']]), ['A', 'B', 'C', 'E', 'D', 'F']);
} お題:W*Hの行列に迷路を生成してください(アルゴリズムは任意)
>>769 解がないため不成立
inputとoutputの事例などがないため不成立
【問題】
整数のリストが与えられたとき、そのリストを昇順に安定ソートした時の各要素のインデクス(0開始)を対応させたリストを作成せよ
【例】
入力: 1 100 10 10000 1000
出力: 0 2 1 4 3
入力: 3 1 4 1 5 9 2
出力: 3 0 4 1 5 6 2
入力: 0 1 0 1 0 1 0 1
出力: 0 4 1 5 2 6 3 7
実際に必要になって実装したけどスマートな方法があったら知りたい
>>771 例がおかしい
わかりやすい最後の例で示すと
入力: 0 1 0 1 0 1 0 1
出力: 0 4 1 5 2 6 3 7 間違い
出力: 0 2 4 6 1 3 5 7 正解
安定ソートなので同値は順序を保ってこうなる
>>772 出題者だけど「各要素の移動先のインデクス」って書いた方がよかったか
文言削りすぎた
>>771 SQL
select
row_number() over(order by arrayValue, arrayIndex) - 1
from
arrayTable
order by
arrayIndex
>>771 ruby 2.6以降?
sorti = ->a {a.map.with_index.sort.map &:last}
f = sorti << sorti
g = method(:p) << f
>>771 R
https://ideone.com/ctaQC5 統計用言語だけあってライブラリ関数rankを呼び出すだけ。ties.method = "min"を指定すれば
同値を同順位(例えば2番目の例では出力が3 0 4 0 5 6 2となる)にもできる。
>>771 Rust
既に色々と出ているため別の観点からのコード
一時作業メモリ最小 & ソートは1回 & ジェネリック
fn f<T: std::cmp::Ord>(input: &[T]) -> Vec<usize> {
let len = input.len();
// ポジションのリスト [0, 1, 2, 3, ... , len-1] を作成
let mut pos_list: Vec<usize> = (0..len).collect();
// inputを利用してそのポジションだけをソート
pos_list.sort_by_key(|&pos| &input[pos]);
// 返すべきランクのリスト
let mut rank_list: Vec<usize> = vec![0; len];
// ポジション⇔ランクは逆写像なのでソートは不要
(0..len).for_each(|rank| rank_list[pos_list[rank]] = rank);
rank_list
}
fn main() {
assert_eq!(f(&[1, 100, 10, 10000, 1000]), [0, 2, 1, 4, 3]);
assert_eq!(f(&[3, 1, 4, 1, 5, 9, 2]), [3, 0, 4, 1, 5, 6, 2]);
assert_eq!(f(&[0, 1, 0, 1, 0, 1, 0, 1]), [0, 4, 1, 5, 2, 6, 3, 7]);
}
>>771 >>776をKotlinに変換してKotlinらしくなるように色々省略しただけのもの。
やはり最初からラムダとか考慮されている言語だと色々省略できて分り易くなるね。
https://paiza.io/projects/0Dhknk4mUHrMqtuwzCDAxQ >>771 Rust
https://ideone.com/jYX2ws バイナリヒープ使うとソート過程で直接リスト作れるけどコード量増えるしヒープソート遅いから実用性は微妙か
C言語ならありかもしれない
>> 771
java
>> 785氏のデータも加えてみた。
https://ideone.com/vzXoGd ideoneのjavaはバージョン古いのか...
ま、通りがかりにこのスレみつけたのでちょっと書いただけ。
ち、勘が鈍った。>>もつけ間違えるし、sage忘れるし。
>>771 java
>>789を修正。何度もすいませんね。classをメソッド内に移動。
https://ideone.com/BV5FXe >>771 java
>>790修正。classだったらメソッドの引数がみえるので修正。recordではできない。
https://ideone.com/r6T4Zf class ValueWithIndex<U /*extends Comparable<U>*/> implements Comparable<ValueWithIndex<T>> {
ジェネリックは難しい。上のextends Comparable<U>は無くてもよいのだが、無駄でも明記したほうがよさそうなので、
ソースではそうした。
明記しなくとも、Uは正しく推測されているようだ。
>>771 dart 2.3
https://ideone.com/XLI2nC ・拡張メソッドはDart2.7から
・ideone現状はDart (dart 2.3.0)
>>771
PowerShell 6以降
function rank($a)
{
$n = $a.length
$r = [int[]]::new($n)
if ($n) {0..($n - 1) | sort-object -stable {$a[$_]} |% {$i = 0} {$r[$_] = $i++}}
$r
}
function PrintArray($a)
{
if ($a.length -le 1) {return $a}
"[$(($a |% {PrintArray $_}) -join ", ")]"
}
$q =
(1, 100, 10, 10000, 1000),
(3, 1, 4, 1, 5, 9, 2),
(0, 1, 0, 1, 0, 1, 0, 1),
@(),
1,
((1, 1), (1, 1), (1, 0, 1), (1, 0))
$q |% {
"入力: $(PrintArray $_)"
"出力: $(PrintArray (rank $_))"
""
} -- 実行結果 --
入力: [1, 100, 10, 10000, 1000]
出力: [0, 2, 1, 4, 3]
入力: [3, 1, 4, 1, 5, 9, 2]
出力: [3, 0, 4, 1, 5, 6, 2]
入力: [0, 1, 0, 1, 0, 1, 0, 1]
出力: [0, 4, 1, 5, 2, 6, 3, 7]
入力:
出力:
入力: 1
出力: 0
入力: [[1, 1], [1, 1], [1, 0, 1], [1, 0]]
出力: [2, 3, 1, 0]
【問題A】
1~9を1つずつ使用して表される9桁の数Anは全部で9!(=362880)個存在する。
整数n(1≦n≦362880)が与えられたとき、n番目に小さいAnを求めよ。
(例)
1 → 123456789
2 → 123456798
3 → 123456879
123456 → 416589732
234567 → 684753219
362880 → 987654321
【問題B】
1~4を3つずつ使用して表される12桁の数Bnは全部で12!/(3!)^4(=369600)個存在する。
整数n(1≦n≦369600)が与えられたとき、n番目に小さいBnを求めよ。
(例)
1 → 111222333444
2 → 111222334344
3 → 111222334434
123456 → 222331434114
234567 → 324424331112
369600 → 444333222111
※求める数値は文字列または各桁の数の配列による表現も可能とする(123⇔"123"⇔[1,2,3])
>>799 Rust 愚直にn回まわし
use itertools::Itertools; // for tuple_windows()
fn f(init: &str, n: usize) -> String {
let mut list = init.chars().rev().collect::<Vec<_>>();
for _ in 1..n {
if let Some((pre_index, (_, old))) = list.iter().tuple_windows().enumerate().find(|(_, (pre, cur))| pre > cur) {
let old_index = pre_index + 1;
let (new_index, _) = list.iter().enumerate().find(|(_, cur)| cur > &old).unwrap();
list.swap(old_index, new_index);
list[..old_index].reverse();
}
}
list.into_iter().rev().collect()
}
fn main() {
assert_eq!(f("123456789", 1), "123456789");
assert_eq!(f("123456789", 2), "123456798");
assert_eq!(f("123456789", 3), "123456879");
assert_eq!(f("123456789", 123456), "416589732");
assert_eq!(f("123456789", 234567), "684753219");
assert_eq!(f("123456789", 362880), "987654321");
assert_eq!(f("111222333444", 1), "111222333444");
assert_eq!(f("111222333444", 2), "111222334344");
assert_eq!(f("111222333444", 3), "111222334434");
assert_eq!(f("111222333444", 123456), "222331434114");
assert_eq!(f("111222333444", 234567), "324424331112");
assert_eq!(f("111222333444", 369600), "444333222111");
} >>799 の問題A
1からnまでの自然数を並べてできるi番目の順列を求める関数を前に作って持っていたので、
それを流用したらすぐできた(元の関数はBigIntとiの範囲外エラーにも対応)。
R
https://ideone.com/hMTf2k C++
https://ideone.com/ZiU5Aa >>799 >>802 のC++のithDuplicatedPermutation関数は引数が別の値(例えばn = 5, m = 3)のとき
正しく計算できなかったので修正。Rの方はintではなくdoubleで計算しているので問題ない。
https://ideone.com/uH8dpO ソートが消えて
>>800と同じアルゴリズムになったね
>>804 確かにそうだった。15!も14!もintの範囲内に収まらない。
>>803でn = 5に変えた場合に正しい
出力になるのはたまたまだった。
>>802をBigInt化するだけで問題なかった。
R
https://ideone.com/OgBxTJ C++
https://ideone.com/KLqe3g >>799 問題A
perl
use v5.42;
sub nthPermutation($digits, $rank) {
my @figures = (1..$digits);
my @fact = (1);
push @fact, $_ * $fact[-1] for @figures;
return join "", map { splice(@figures, $_, 1) } sub($n, $r) {
$n-- ? (int($r / $fact[$n]), __SUB__->($n, $r % $fact[$n])) : ();
}->($digits, $rank - 1);
}
for my $i (1, 2, 3, 123456, 234567, 362880) {
say "$i -> " . nthPermutation(9, $i);
}
1 -> 123456789
2 -> 123456798
3 -> 123456879
123456 -> 416589732
234567 -> 684753219
362880 -> 987654321 >>799 の逆変換プログラム
R
https://ideone.com/TU73Yu C++
https://ideone.com/dmETd5 問題A, 問題Bとは違って、順列に出現するユニークな整数は1〜nの連番でなくても良いし、
出現回数はすべて同じでなくても良い。例えば、入力は [3, 1, 4, 1, 5, 9] でも良い
(ユニークな整数は1, 3, 4, 5, 9で、出現回数は1が2回、その他が1回)。
>>812 Rust
>>799の逆変換の重複順列の何番目か算出
use itertools::Itertools;
use num::{BigUint, One};
// 重複順列の何番目かを求める ex. "222331434114" → "123456"番目
fn to_nth(input: &str) -> String {
// 出現数
let (mut counts, chars): (Vec<usize>, Vec<char>) = input.chars().sorted().dedup_with_count().multiunzip();
// index化input
let input: Vec<usize> = input.chars().map(|c| chars.iter().position(|&c0| c0 == c).unwrap()).collect();
// 階乗関数
fn factorial(x: usize) -> BigUint { (1..=x).fold(BigUint::one(), |p, x| p * x) }
// 重複順列の総数
let mut whole: BigUint = factorial(input.len()) / counts.iter().map(|&x| factorial(x)).product::<BigUint>();
// nth番目を算出
(1..=input.len()).rev().zip(input).fold(BigUint::one(), |mut nth, (len, index)| {
// 自分より前までの総数をnthに足す
nth += &whole * counts[..index].iter().sum::<usize>() / len;
// 自分の総数へ更新
whole *= counts[index];
whole /= len;
counts[index] -= 1;
nth
})
.to_string()
}
>>814の検証分
fn main() {
assert_eq!(to_nth("123456789"), "1");
assert_eq!(to_nth("123456798"), "2");
assert_eq!(to_nth("123456879"), "3");
assert_eq!(to_nth("416589732"), "123456");
assert_eq!(to_nth("684753219"), "234567");
assert_eq!(to_nth("987654321"), "362880");
assert_eq!(to_nth("111222333444"), "1");
assert_eq!(to_nth("111222334344"), "2");
assert_eq!(to_nth("111222334434"), "3");
assert_eq!(to_nth("222331434114"), "123456");
assert_eq!(to_nth("324424331112"), "234567");
assert_eq!(to_nth("444333222111"), "369600");
assert_eq!(to_nth("111333442545225"), "123456");
assert_eq!(to_nth("555444333222111"), "168168000");
assert_eq!(to_nth("11111222223333344444555556666677777899⑩⑩889889⑩⑩⑩9"), "123456");
assert_eq!(to_nth("⑩⑩⑩⑩⑩999998888877777666665555544444333332222211111"), "49120458506088132224064306071170476903628800");
assert_eq!(to_nth("314159"), "127");
assert_eq!(to_nth("3141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067"), "11503448027594046007734790817193859678406683579515952737315863863451534425766911708030454269");
assert_eq!(to_nth("なまむぎなまごめなまたまご"), "10515454");
assert_eq!(to_nth("かえるぴょこぴょこみぴょこぴょこあわせてぴょこぴょこむぴょこぴょこ"), "8273693808428448039784");
}
>>799 ruby
https://ideone.com/vvp0kq ・問題A時に全体的な規則性に着目
・部分的に着目しちゃったのが
>>811 ・何も工夫を入れなかったのが
>>806 >>812の逆変換プログラムは
>>808の順変換プログラムを流用したから処理に無駄があった。
逆変換用に一から書き直したらすっきりした。
R
https://ideone.com/jYUHe1 C++
https://ideone.com/Lne3AQ >>820の逆変換プログラムのC#版
https://ideone.com/8HpCN9 LINQのTakeWhileメソッドとSumメソッドを組み合わせたらすっきり書けた。
>>799 java
https://ideone.com/aKkfqN ・next()ごとに複製しない版。する版は
>>821 ・hasNext()側で次を準備。next()側なのは
>>821 >>802をCMD (Windowsバッチファイル) に移植
@echo off & setlocal EnableDelayedExpansion
echo 【問題A】
for %%i in (1, 2, 3, 123456, 234567, 362880) do call :ithDuplicatedPermutation 9 1 %%i
echo.
echo 【問題B】
for %%i in (1, 2, 3, 123456, 234567, 369600) do call :ithDuplicatedPermutation 4 3 %%i
exit /b
:ithDuplicatedPermutation
set /a n = %1, m = %2, i = %3, L = 0, P = 1
for /l %%j in (1, 1, %n%) do (
set /a c%%j = %m%
for /l %%k in (1, 1, %m%) do set /a L += 1, P = P * L / %%k
)
set a=%i% →
for /l %%j in (1, 1, %L%) do (
set /a done = 0
for /l %%k in (1, 1, %n%) do (
if !done! equ 0 (
set /a "q = P * c%%k / (L - %%j + 1)"
if !i! leq !q! (
set a=!a!%%k
set /a c%%k -= 1, P = q, done = 1
) else (
set /a i -= q
)
)
)
)
echo %a% -- 実行結果 --
【問題A】
1 → 123456789
2 → 123456798
3 → 123456879
123456 → 416589732
234567 → 684753219
362880 → 987654321
【問題B】
1 → 111222333444
2 → 111222334344
3 → 111222334434
123456 → 222331434114
234567 → 324424331112
369600 → 444333222111
>>812 scheme (chicken 4.13)
https://ideone.com/fZufck ・集計部分をalistに変えてみただけ
>>561 scheme (chicken 4.13)
https://ideone.com/8VZv71 ・m1m2を不必要にリストにしてたのを廃止
>>561 scheme (chicken 4.13)
https://ideone.com/EsJWtG ・letを自然な位置に移動
>>485 scheme (chicken 4.13)
https://ideone.com/ejvKat ・(product . lists)
・(product xs . rest) が
>>835 >>438 scheme (chicken 4.13)
https://ideone.com/6weUjU ・まずまとまりに分割して処理
>>438 scheme (chicken 4.13)
https://ideone.com/BCt6fd ・最初のを四つにして、残りはスキップ
>>438 C#で短く書けた
https://ideone.com/SwAZsS x.EndsWith(" ") でなく x.LastOrDefault() == ' ' の方が長くはなるが効率的かも知れない。
>>485 scheme (chicken 4.13)
https://ideone.com/g8wtFG ・デカルト積の解釈を(勝手に)変更
>>485 scheme (chicken 4.13)
https://ideone.com/A6K3XL ・(cons y x)して最後にreverseする
・(list x y)して最後にflattenするのが
>>839 >>485 scheme (chicken 4.13)
https://ideone.com/YqrvdM ・reverse回数減らした版
お題
1行1単語のリストが、しりとりとして成立しているか判定するコードを書きなさい
成立していたら◯、不成立なら☓をしゅつりょくすること
【入力】
りんご
ごりら
らっぱ
入力例に対する出力例が存在しなくて曖昧
それを補わないと問題が不成立
退屈そうだからちょっと難易度高め
【問題】
各桁の数が1~5のいずれかで全ての桁の合計がMとなる正整数の集合をG[M]で表す。
例えば123、111111はG[6]の要素、255、222222はG[12]の要素となる。
整数M(1≦M≦32)、N(1≦N)が与えられたとき、N番目に小さいG[M]の要素を求めよ。
ただしNがG[M]の要素数より大きい場合の出力は0とする。
求める数値は文字列または各桁の数の配列による表現も可能とする(123⇔"123"⇔[1,2,3])。
【例】 #入力は(M,N)
(2,1) → 2
(2,2) → 11
(2,3) → 0
(20,1) → 5555
(20,2) → 14555
(20,3) → 15455
(20,400096) → 11111111111111111111
(20,400097) → 0
(32,1) → 2555555
(32,2) → 3455555
(32,3) → 3545555
(32,1000) → 34355354
(32,1000000) → 11532334334
(32,1000000000) → 2141111311212411131
(32,1333610936) → 11111111111111111111111111111111
(32,1333610937) → 0
【ヒント(?)】
G[M]の要素数の数列は下記pentanacci数列a[n]から先頭の[0,0,0,0,1]を除いたものとなる(|G[M]| = a[M + 4])。
・a[0,1,2,3,4] = [0,0,0,0,1]
・a[k] = a[k-1] + a[k-2] + a[k-3] + a[k-4] + a[k-5] (k≧5)
※a[37]までのリスト:
https://oeis.org/A001591/list >>845 ruby
https://ideone.com/wrV2zh ・なんとなく動いてる版
・チマチマと次を探して行く
・G[20]まで出すのがやっと(4.05s)
>>845 Fortranに移植
https://ideone.com/CnJ0S9 行列計算を短く書けて、しかも実行が速い。
>>845 ruby
https://ideone.com/3I72I6 ・キャッシュ探りながら構築
・c[桁の合計][幅] = とりうるパターン
>>850では行末に無駄な半角空白文字が出力される。消すには最後から3行目のnthPartition(m, n)を
trim( )で囲めば良い。
>>845 ruby
https://ideone.com/n5Jqm3 ・動きは
>>851 といっしょ
・数値の内部表現を配列から整数へ変更
>>845 ruby 2.5.5
https://ideone.com/oAQimi ・とりうるパターン数に着目し迫る
・tallyは2.7以降
>>845 C++
https://ideone.com/I6K1tl 行列Aの計算で加減算・代入回数を
>>849より減らした。実行時間の違いは分からなかった。
>>856 BigInt化してm = 2000, n = 2¹⁰²⁴で実行したら違いが明確になった。
(1)
>>849のBigInt版
https://ideone.com/S92L9G (2)
>>856のBigInt版
https://ideone.com/3x03xT 加減算・代入回数を削減した(2)の方が確かに速く、(1)の約4分の3の実行時間。
>>845 ruby 2.5.5
https://ideone.com/Zm2433 ・揃ってからcumsum、のリズムを廃止
>>845 ruby 2.5.5
https://ideone.com/iwQNCH ・若干の整理(loop廃止、fill三回へ置き換え)
>>845 ruby 2.5.5
https://ideone.com/jHqv2L ・内部表現の変更
112225→[2,3,0,0,1]
>>845 ruby 2.5.5
https://ideone.com/MDHX6v ・内部表現のさらなる変更
・パターン数を直接キャッシュするようにした
cc[合計][幅] = とりうるパターン数
>>845 ruby
https://ideone.com/PB8S7w ・m = 2000, n = 1 << 1024
>>845 c++
https://ideone.com/oma0Jf ・ruby版861の移植
・m = 2000, n = 1 << 1024
>>845 ruby
https://ideone.com/YEGl7C ・実りの無い再帰を省略
・結果を配列で集めず整数で集める
>>845 c++
https://ideone.com/f62fkG ・rubyの移植版
>>845 ocaml
https://ideone.com/cHYmdv ・rubyの移植版
・任意精度整数は昔ながらのnumのBig_int使用
・ZarithのZは確かに速かったけどideoneでは使えずボツ
お題
硬貨の種類と金額が与えられます。
硬化の合計がちょうど金額と同じになるように硬貨を選ぶとき、使用枚数の最小値を求めてください。
支払いが不可能なときは-1を出力します。
各硬貨は無制限に使用できます。
額面の大きい硬貨を優先して選ぶ貪欲法が常に最適解を与えるとは限らないことに注意。
入力
硬貨:[1,7,10]
金額:14
出力
使用枚数:2
お題というか、協力してほしい感じなんですが、素因数分解関数をHaskellで書いて色んな数を素因数分解して遊んでいたら確認したい事実に出くわしたので。
31 <- 素数
331 <- 素数
3331 <- 素数
33331 <- 素数
333331 <- 素数
と、3が5個並んで末尾が1の数字までは素数という事が分かりましたが、いかんせん、ノートだと力不足。
それにCとかで書き直したらもっと先まで行けるかも?という事で、この先、どこまで33...31が素数なのかを調べて欲しいのです。
協力お願いします<(_ _)>
一応、Haskellではこんなコードです。
factorization n = f primes n
where primes = 2:(sieve [3,5..])
where sieve (p:xs) = p:(sieve [x | x <- xs, x `mod` p /= 0])
f (p:ps) n | n <= p = [n]
f (p:ps) n | n `mod` p == 0 = p:f (p:ps) (n `div` p)
f (p:ps) n = f ps n
あ、ただの素数判定でも良いです。
ちなみに、66..61の場合は6661までは素数ですが66661は素数じゃなくなりました。
なので、33..31もどこかで素数じゃなくなるのか?それともずっと素数になりそうなのか?って疑問が持ち上がりました。
>>867 興を削いですまんが、「33...331は素数か」でググったら、AIが(あまり大きくない桁数で)答えを示してくれた…
near-repdigit素数とかで研究されてるらしい
結果だけ知りたいなら↓がまとめてる
https://stdkmd.net/nrr/3/33331.htm >>869 ちなみに、以下の思考経路だったのでプログラミング的な思考がゼロだった訳では無い。
1.多倍長整数で組むべきかな?
2.でも64bit整数の範囲で合成数だったら馬鹿馬鹿しいな
3.組む前にカンニングしちゃえ
4.
>>869 >>869-871 いえいえ、ああ、やっぱりずっと素数という訳にはいかないんですね…。
何か素数の秘密に触れるヒントか?と心躍ったけど、そんな訳なかったですね(´・ω・`)
あやうく数学スレで鼻息荒く書き込むところでした。
ありがとうございました<(_ _)>
29bitで収まる範囲内
333333331 = 17 × 19607843
これを求められなかったHaskellはすごく遅い?
>>873
速いアルゴリズムに変えたら何とか1分ほどでその数字まで届きました。
(そもそも、>867 のは美しいとか短いとかの枕詞が付くコードですし。33...31に気付かなかったら4桁ぐらいが実用的ならおkだったので)
改良版Haskell
pfactorization = f primes
where primes =2:3:5#primes
where n#x@(m:q:y)=[n|gcd m n<2]++(n+2)#last(x:[m*q:y|q^2-3<n])
というか、それより1桁少ない方が少し時間かかりますね。
19607843 < 33333331 なので、素数比較回数が多いのかと。 あ、f の方を忘れた。
f のコードは変更なしです。
>>868 cだとこんな感じでいいのかな?
3333333333333331くらいまで一瞬でできる
#include <stdio.h>
int main(void) {
long long d, n;
printf("Enter a number: ");
scanf("%lld", &n);
for (d = 2; d * d <= n; d++) {
if (n % d == 0)
break;
}
if (d * d <= n)
printf("%lld is divisible by %lld\n", n, d);
else
printf("%lld is prime.\n", n);
return 0;
}