トップページに戻る    次の競技プログラミングの問題へ    前の競技プログラミングの問題へ

川添さん問題10 アフター・ドット

■■■問題■■■

自然数 n に対し、1 <= a <= n, 1 <= b <= n を満たし、
かつ小数で表した a÷b が有限小数となるような自然数の組 (a, b) の個数を F(n) と定義します。
(有限小数 ・・・ 小数点以下の桁数が有限である小数)

例えば、F(3) = 7 です。
下記の(a, b)の組のうち、有限小数は赤字で記した7個です。

●1÷1=1, 1÷2=0.5, 1÷3=0.33333・・・
●2÷1=2, 2÷2=1,  2÷3=0.66666・・・
●3÷1=3, 3÷2=1.5, 3÷3=1

同様に、F(5)=21 , F(10)=68 , F(100)=2185 となることが確かめられます。

標準入力から、自然数 n (1 <= n <= 1万) が与えられます。
標準出力に F(n)の値を出力するプログラムを書いてください。


C#のソース

using System;
using System.Collections.Generic;

class Program
{
    static string InputPattern = "InputX";

    static List<string> GetInputList()
    {
        var WillReturn = new List<string>();

        if (InputPattern == "Input1") {
            WillReturn.Add("3");
            //7
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("5");
            //21
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("10");
            //68
        }
        else if (InputPattern == "Input4") {
            WillReturn.Add("100");
            //2185
        }
        else if (InputPattern == "Input5") {
            WillReturn.Add("10000");
            //最悪計算量
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static int[] SosuuArr;

    //エラトステネスの篩で上限以下の素数の配列を作成
    static void Eratosthenes(int pJyougen)
    {
        var IsSosuuArr = new System.Collections.BitArray(pJyougen + 1);
        for (int I = 2; I <= IsSosuuArr.Count - 1; I++) {
            IsSosuuArr[I] = true;
        }
        for (int I = 2; I * I <= IsSosuuArr.Count - 1; I++) {
            if (IsSosuuArr[I] == false) continue;
            for (int J = I * 2; J <= IsSosuuArr.Count - 1; J += I) {
                IsSosuuArr[J] = false;
            }
        }
        var SosuuList = new List<int>();
        for (int I = 2; I <= IsSosuuArr.Count - 1; I++) {
            if (IsSosuuArr[I]) SosuuList.Add(I);
        }
        SosuuArr = SosuuList.ToArray();
    }

    static void Main()
    {
        List<string> InputList = GetInputList();
        int N = int.Parse(InputList[0]);

        Eratosthenes(N);

        //自然数の個数[2と5以外の素因数の積]なDict
        var ProdValDict = new SortedList<int, int>();

        for (int I = 1; I <= N; I++) {
            int wkKey = DeriveProdVal(I);
            if (ProdValDict.ContainsKey(wkKey))
                ProdValDict[wkKey]++;
            else ProdValDict[wkKey] = 1;
        }

        int Answer = 0;
        foreach (var EachPair1 in ProdValDict) {
            foreach (var EachPair2 in ProdValDict) {
                //分子 < 分母 ならBreak
                if (EachPair1.Key < EachPair2.Key) break;

                //分子が分母の倍数なら有限小数
                if (EachPair1.Key % EachPair2.Key == 0) {
                    //積の法則
                    Answer += EachPair1.Value * EachPair2.Value;
                }
            }
        }
        Console.WriteLine(Answer);
    }

    //2と5以外の素因数の積を求める
    static int DeriveProdVal(int pTarget)
    {
        int WillReturn = 1;
        for (int I = 0; I <= SosuuArr.GetUpperBound(0); I++) {
            while (pTarget % SosuuArr[I] == 0) {
                pTarget /= SosuuArr[I];
                if (SosuuArr[I] != 2 && SosuuArr[I] != 5) {
                    WillReturn *= SosuuArr[I];
                }
            }
            if (pTarget < SosuuArr[I]) break;
        }
        return WillReturn;
    }
}


解説

各自然数を、2と5以外の素因数の積に、変換してから、
割り算の結果が有限小数になるかを判定してます。

ProdValDictの2重ループで、
SortedDictionaryだと1.5秒かかって処理が、
SortedListに変えると半分になりました。
列挙は、SortedListに分があるようですね。