AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC280-D Factorial and Multiple
C#のソース
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static string InputPattern = "InputX";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("30");
//5
}
else if (InputPattern == "Input2") {
WillReturn.Add("123456789011");
//123456789011
}
else if (InputPattern == "Input3") {
WillReturn.Add("280");
//7
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static Dictionary<long, long> mSoinsuuDict;
static void Main()
{
List<string> InputList = GetInputList();
long K = long.Parse(InputList[0]);
mSoinsuuDict = DeriveSoinsuuDict(K);
long L = 1;
long R = K;
while (L + 1 < R) {
long Mid = (L + R) / 2;
if (CanAchieve(Mid)) {
R = Mid;
}
else {
L = Mid;
}
}
Console.WriteLine(R);
}
// pXで達成できるかを返す
static bool CanAchieve(long pX)
{
foreach (var EachPair in mSoinsuuDict) {
long CurrDivCnt = Legendre(pX, EachPair.Key);
if (CurrDivCnt < EachPair.Value) return false;
}
return true;
}
// ルジャンドルの定理で
// Nを引数として、Nの階乗を素数Primeで何回割れるかを求める
static long Legendre(long pN, long pPrime)
{
long TotalDivCnt = 0;
long Sobeki = pPrime;
while (true) {
long CurrDivCnt = pN / Sobeki;
if (CurrDivCnt == 0) return TotalDivCnt;
TotalDivCnt += CurrDivCnt;
Sobeki *= pPrime;
}
}
// 素因数分解し、指数[素数]なDictを返す
static Dictionary<long, long> DeriveSoinsuuDict(long pTarget)
{
var WillReturn = new Dictionary<long, long>();
long CurrVal = pTarget;
// ルートより大きい数を、素因素に持つとしても、1つだけのため
// ルートまで試し割りを行い、素因数が残っていたら、追加する
for (long I = 2; I * I <= pTarget; I++) {
if (CurrVal % I > 0) continue;
WillReturn[I] = 0;
while (CurrVal % I == 0) {
WillReturn[I]++;
CurrVal /= I;
}
if (CurrVal == 1) break;
}
// 素因数が残っている場合
if (CurrVal > 1) {
WillReturn[CurrVal] = 1;
}
return WillReturn;
}
}
解説
二分探索の判定メソッドで、ルジャンドルの定理を使ってます。