日本人いっぱい


定員1500人を超えたとかで参加できない人もいるみたい。


500点問題をなんども間違っていないかテストしたりテストケース追加したりしたんだけど、これ与えられているテストケースがコーナーケースじゃないの。さっさとサブミットしてしまった方がよかったのかなぁ。そして残り10分でC++幅優先探索のコードを書く力量は僕にはない。今後の課題にする。


このあと一人だけ1000点を解いた。僕4位だからダメ元で迎撃する。

ダメ元で迎撃しようと用意しておいたテストケースを貼ろうとしたらそうだったコピペできないんだった。なれないGUIでテストケース作ってたら誰かに先に撃墜されてた。

なんか2位。練習に1位の人を攻撃してみよう。

。。。なんか間違いを犯した気がする。チャレンジ失敗のペナルティで3位と逆転したっぽい。


システムテストの結果:

先生、うちのクラスは500点問題全滅なんですけど><


まぁ、理由はだいたい想像がつくが。うーむ。どういう戦略が正解だったのかなぁ。

        • -

500点問題の解説。ある数が与えられたときに、その数が「素数のn乗」であるかどうかを判定せよ、という問題。nは2以上。返す値は、素数のn乗ではないとき空のvector、pのn乗であるとき{p, n}。これで与えられる数の範囲が狭ければまだいいが、恐ろしいことに「与えられる数は2以上10^18以下とする」とな。引数が文字列で与えられるからてっきりlong longに収まらないと思い込んでしまったが、収まるよね。

>>> 2 ** 63
9223372036854775808L
>>> 10 ** 18
1000000000000000000L

探すべき空間が広いので、順番に探したりしたら全然間に合わない。というわけでpow(x, 1.0/3.0)とかしてみた。xがなんらかの整数のn乗であるかどうかは、pow(x, 1.0 / n)の値を切り捨ててプラスマイナス1くらいの範囲でn乗してみてxと一致するかどうかをチェック。

  vector <int> baseAndExponent(string n) {
    LL v = lexical_cast<LL>(n);
    for(size_t i=2; i<10000; i++){
      double d = pow(v, 1.0/i);
      if(d < 2.0) break;
      cout << d << endl;
      LL start(d - 1);
      LL end(d + 2);
      for(size_t j=start; j<end; j++){
	LL power = 1;
        for(size_t k=0; k<i; k++){
	  power *= j;
	}
	if(power == v){
	  // is prime?
	  bool isPrime = true;
	  LL ubound(sqrt(j)+1);
	  for(size_t x=2; x<ubound; x++){
	    if(j % x == 0){
	      isPrime = false;
	      break;
	    }
	  }
	  if(j < 4) isPrime = true;
	  if(isPrime){
	    vector<int> result;
	    result.push_back(j);
	    result.push_back(i);
	    return result;
	  }
	}
      }
    }
    vector<int> result;
    return result;
  }

浮動小数点数の切り捨ての仕方がわからないのでwarningを無視してむりやり整数に。システムテストに落ちた原因はここ

	LL power = 1;
        for(size_t k=0; k<i; k++){
	  power *= j;
	}
	if(power == v){

「jをk乗して、vに一致するなら」のつもりだったけども、これが入力が639558602475808609の時に2.07952の56乗になって、プラス1の3の56乗がオーバーフローを繰り返した結果なんと入力に一致するという罠。

3
9
27
81
243
729
2187
(snip)
6048575297968530377
-301018179803960485
-903054539411881455
-2709163618235644365
-8127490854706933095
-5935728490411247669
639558602475808609

うあー。オーバーフローの可能性にもっと敏感にならなきゃ行けないんだなぁ。
気づいていれば「if(power < 0) break;」の一言で一位になれたんだけどな。まだまだ道のりは長い。

        • -

次回の目標
□ 500点問題を取る
□ 掛け算、足し算を見たらオーバーフローを疑え