3つの自然数a,b,cに対し、これらを係数に持つ次の二次方程式を考えます。 a*x*x + b x + c = 0 ・・・ (※) 例えば、(a,b,c) = (1,6,4) のとき、方程式(※)は、x*x + 6x + 4 = 0 となります。 この方程式は実数解を持ちます。x = -3+ルート(5) と x = -3-ルート(5) の2つです。 一方で、(a,b,c) = (1,6,10) のとき、方程式(※)は実数解を持ちません。 b <= 3 の範囲で、 方程式(※)が少なくとも1つの実数解を持つような自然数の組 (a,b,c)は、全部で4組あります。 (a,b,c) = (1,2,1), (1,3,1), (1,3,2), (2,3,1) です。 自然数 m に対し、 b <= m の範囲で方程式(※)が少なくとも1つの実数解を持つような 自然数の組(a,b,c)の個数をF(m)と定義します。 例えばF(3)=4、F(4)=12、F(10)=287、F(100)=620174 です。 標準入力から、自然数m (1 <= m <= 3000) が与えられます。 標準出力に F(m) の値を出力するプログラムを書いてください。
using System;
using System.Collections.Generic;
class Program
{
static string InputPattern = "Input1";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("3");
//4
}
else if (InputPattern == "Input2") {
WillReturn.Add("4");
//12
}
else if (InputPattern == "Input3") {
WillReturn.Add("10");
//287
}
else if (InputPattern == "Input4") {
WillReturn.Add("100");
//620174
}
else if (InputPattern == "Input5") { //最悪計算量
WillReturn.Add("3000");
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static void Main()
{
List<string> InputList = GetInputList();
int m = int.Parse(InputList[0]);
//b*b - 4*a-c >=0
//b*b >= 4*a*c
//bとaを固定して、cの解の数を求める
long AnswerCnt = 0;
for (int b = 1; b <= m; b++) {
int Sahen = b * b / 4; //小数部を切り捨て可能な不等式
//計算量を減らすため、a<=cとする
for (int a = 1; Sahen >= a * a; a++) {
int MaxC = Sahen / a; //小数部を切り捨て可能な不等式
int wkCnt = MaxC - a + 1; //a<=cを満たすcのみカウント
wkCnt *= 2; //a<=cを解除して場合の数を調整
wkCnt--; //a==cの分を引く
AnswerCnt += wkCnt;
}
}
Console.WriteLine(AnswerCnt);
}
}
計算量を減らすため、a<=cとして、 後で場合の数を調整してます。 「セカンド・イクエイション」問題解説 --- CodeIQ MAGAZINE