3.1 KiB
		
	
	
	
	
	
	
	
			
		
		
	
	
			3.1 KiB
		
	
	
	
	
	
	
	
id, title, challengeType, forumTopicId, dashedName
| id | title | challengeType | forumTopicId | dashedName | 
|---|---|---|---|---|
| 5900f3ae1000cf542c50fec1 | 問題 66: ディオファントス方程式 | 5 | 302178 | problem-66-diophantine-equation | 
--description--
次のような二次のディオファントス方程式を考えます。
x2 – Dy2 = 1
例えば、D=13 のとき、x の最小解は 6492 – 13×1802 = 1 です。
D が平方数のとき、正整数の中に解は存在しないと想定できます。
D = {2, 3, 5, 6, 7} に対する x の最小解を求めると、以下が得られます。
  32 – 2×22 = 1
22 – 3×12 = 1
92 – 5×42 = 1
52 – 6×22 = 1
82 – 7×32 = 1
22 – 3×12 = 1
92 – 5×42 = 1
52 – 6×22 = 1
82 – 7×32 = 1
したがって、D ≤ 7 に対する x の最小解を考えると、D=5 のときに x が最大になります。
x が最大になるような 、x の最小解における値 D (≤ n) を求めなさい。
--hints--
diophantineEquation(7) は数値を返す必要があります。
assert(typeof diophantineEquation(7) === 'number');
diophantineEquation(7) は 5 を返す必要があります。
assert.strictEqual(diophantineEquation(7), 5);
diophantineEquation(100) は 61 を返す必要があります。
assert.strictEqual(diophantineEquation(100), 61);
diophantineEquation(409) は 409 を返す必要があります。
assert.strictEqual(diophantineEquation(409), 409);
diophantineEquation(500) は 421 を返す必要があります。
assert.strictEqual(diophantineEquation(500), 421);
diophantineEquation(1000) は 661 を返す必要があります。
assert.strictEqual(diophantineEquation(1000), 661);
--seed--
--seed-contents--
function diophantineEquation(n) {
  return true;
}
diophantineEquation(7);
--solutions--
function diophantineEquation(n) {
  // Based on https://www.mathblog.dk/project-euler-66-diophantine-equation/
  function isSolution(D, numerator, denominator) {
    return numerator * numerator - BigInt(D) * denominator * denominator === 1n;
  }
  let result = 0;
  let biggestX = 0;
  for (let D = 2; D <= n; D++) {
    let boundary = Math.floor(Math.sqrt(D));
    if (boundary ** 2 === D) {
      continue;
    }
    let m = 0n;
    let d = 1n;
    let a = BigInt(boundary);
    let [numerator, prevNumerator] = [a, 1n];
    let [denominator, prevDenominator] = [1n, 0n];
    while (!isSolution(D, numerator, denominator)) {
      m = d * a - m;
      d = (BigInt(D) - m * m) / d;
      a = (BigInt(boundary) + m) / d;
      [numerator, prevNumerator] = [a * numerator + prevNumerator, numerator];
      [denominator, prevDenominator] = [
        a * denominator + prevDenominator,
        denominator
      ];
    }
    if (numerator > biggestX) {
      biggestX = numerator;
      result = D;
    }
  }
  return result;
}