paiza予想《素数・エラトステネスの篩》

素数メニュー【ゴールドバッハ予想・中国剰余定理・paiza予想】

【ゴールドバッハ予想】コード

reader.on('close', () => {
   const N = Number(lines[0]);
  // ここから…エラトステネスの篩
   const prime = new Array(N + 1).fill(true);  // 0 ~ N が素数か否真偽値 (trueで初期化)
   [prime[0], prime[1]] = [false, false];  // 0 と 1 は 2以下なので false
   for (let i = 2; i * i <= N; i++) {
      if (prime[i]) {  // true のときのみ実行
         for (let j = 2; j * i <= N; j++) {
            prime[i * j] = false;  // 2つの値の積は素数に該当しないので false
         }
      }
   }
   const Prime_number = [];  // 0 ~ N の素数を保存するための配列
   for (let i = 0; i <= N; i++) {
      if (prime[i]) {  // prime[i] が true なら
         Prime_number.push(i);  // i は素数
      }
   }
  // ここまで…エラトステネスの篩
   const Prime_pair = [0, N];  // 和 が N になる 素数 の ペア
   const n = Prime_number.length;
   for (let i = 0; i < n; i++) {
      const [a, b] = [Prime_number[i], N - Prime_number[i]];
      if (a > b) {  // ab より大きくなれば…
         break;  // 処理を止める
      }
      if (Prime_number.includes(b)) { // Prime_numberb が含まれていれば…
         const [c, d] = [...Prime_pair]; // c, d Prime_pair を 展開した値を代入 
         if (a * b > c * d) {  // a × b  > c × d の積なら…
            [Prime_pair[0], Prime_pair[1]] = [a, b];  // Prime_pair の各値を a, b で上書き
         }
      }
   }
   Prime_pair.forEach(p => {
      console.log(p);
   });
});
hogeちゃんの画像

足して N となる 2 つの素数のうち 積が最大であるものを小さい順に 2 行で出力。なので エラトステネスの篩で 0 〜 N に含まれる素数を抽出して その中に含まれる 2つの素数(a >= b)を取出し (a × b)と元の値の積(c × d)を比較しながら Prime_pair の値を更新しています。

【中国剰余定理】コード 1/2

reader.on('close', () => {
   const [m1, m2, b1, b2] = lines[0].split(' ').map(Number);
// m1, m2 は 互いに素である正の整数
// [b1, b2] = [Z % m1, Z % m2]
// Z は [0, m1 * m2) に含まれる唯一の整数
   const n = m1 * m2;
   for (Z = n - 1; Z >= 0; Z--) {  // [0, m1 * m2) の範囲を 降順にループ
      if (Z % m1 === b1 && Z % m2 === b2) {  // Z % m1b1 且つ Z % m2b2 なら…
         console.log(Z);
         break;
      }
   }
});
hogeちゃんの画像

問題文の条件を準えてコーディングすると こんな感じになりました。最初はループを昇順にしていましたが タイムオーバーになったので 降順に書き換えると 時間内にクリアできました。(ー。ー)フゥ

【中国剰余定理】コード 2/2

reader.on('close', () => {
   const [m1, m2, b1, b2] = lines[0].split(' ').map(Number);
// m1, m2 は 互いに素である正の整数
// [b1, b2] = [Z % m1, Z % m2]
// Z は [0, m1 * m2) に含まれる唯一の整数
   for (let i = 0; i < m2; i++) {  // ループの範囲は[0, m2)
      const z1 = m1 * i + b1;  // z1 は [0, m1 * m2) に含まれる b1 = z1 % m1 を満たす整数
      if (z1 % m2 === b2) {  // z1(b1 = z1 % m1 を満たす整数) % m1 が b2 なら… 
         const Z = z1;  // [b1, b2] = [z1 % m1, z1 % m2]を満たすので Z = z1
         console.log(Z);
         break;
      }
   }
});
hogeちゃんの画像

C++の実装例と解説を参照しながら修正すると コード1と比べ 実行速度が上がりました。b1 = z1 % m1 を満たす整数 z1 を求めてから b2 = z1 % m2 を満たすかどうか調べています。(o・。・o)

【paiza予想】コード

let prime = true;
// ゴールドバッハ予想より… 3 より大きな偶数は 2 つの素数の和として表すことができるので…
for (let i = 3; i * i < 10 ** 8; i += 2) {  // 3 より大きな 奇数の…
   const x = i * i;  // 平方数を求めて…
   for (let i = 2; i * i <= x - 2; i++) {  // 2 ~ x - 2 の平方根までループして…
      if ((x - 2) % i === 0) {  // x - 2 が i で割り切れれば…(奇数 + 偶数 = 奇数 になるが 偶数の素数は2のみなので…)
         prime = false;
         console.log(x);  // 2 つの素数の和として表すことができない
         break;
      }
   }
}
if (prime) {
   console.log('paiza\'s conjecture is correct.');
}
hogeちゃんの画像

ゴールドバッハ予想より 3 より大きな偶数は 2 つの素数の和として表すことができることがわかっているので 奇数の平方数について調べればOKでした。

偶数 + 偶数 = 偶数,  奇数 + 奇数 = 偶数,  偶数 + 奇数 = 奇数, 偶数の素数は2のみ…

なので N – 2 が素数に該当しない場合は 2つの素数の和として表すことができないことになります。

コメント