競技プログラミングの鉄則    前の問題へ

C13 Select 2


問題へのリンク


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("4 6");
            WillReturn.Add("1 2 3 6");
            //2
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("4 1");
            WillReturn.Add("1000000008 1000000008 1000000008 1000000008");
            //6
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("2 609777330");
            WillReturn.Add("31415926535897932 384626433832795028");
            //1
        }
        else if (InputPattern == "Input4") {
            WillReturn.Add("10 0");
            WillReturn.Add("0 0 0 0 0 1 2 3 4 5");
            //35
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    const long Hou = 1000000007;

    static void Main()
    {
        List<string> InputList = GetInputList();
        long[] wkArr = InputList[0].Split(' ').Select(pX => long.Parse(pX)).ToArray();
        long P = wkArr[1];

        long[] AArr = InputList[1].Split(' ').Select(pX => long.Parse(pX)).ToArray();
        long Result = Solve(P, AArr);
        Console.WriteLine(Result);
    }

    static long Solve(long pP, long[] pAArr)
    {
        var CntDict = new Dictionary<long, long>();
        foreach (long EachA in pAArr) {
            long Mod = EachA % Hou;
            if (CntDict.ContainsKey(Mod) == false) {
                CntDict[Mod] = 0;
            }
            CntDict[Mod]++;
        }

        // mod 0は最初に計上する
        long Answer1 = 0;
        if (CntDict.ContainsKey(0) && pP == 0) {
            long Syokou = pAArr.Length - 1;
            long Makkou = pAArr.Length - CntDict[0];
            for (long I = Syokou; Makkou <= I; I--) {
                Answer1 += I;
            }
        }
        CntDict.Remove(0);

        long Answer2 = 0;
        long Answer3 = 0;
        foreach (var EachPair in CntDict) {
            long PairMod = pP * DeriveGyakugen(EachPair.Key);
            PairMod %= Hou;
            if (CntDict.ContainsKey(PairMod)) {
                if (EachPair.Key == PairMod) {
                    if (EachPair.Value >= 2) {
                        long Prod = EachPair.Value * (EachPair.Value - 1) / 2;
                        Answer2 += Prod;
                    }
                }
                if (EachPair.Key < PairMod) {
                    long Prod = (EachPair.Value * CntDict[PairMod]);
                    Answer3 += Prod;
                }
            }
        }
        return Answer1 + Answer2 + Answer3;
    }

    // 引数の逆元を求める
    static long DeriveGyakugen(long pLong)
    {
        return DeriveBekijyou(pLong, Hou - 2, Hou);
    }

    // 繰り返し2乗法で、(NのP乗) Mod Mを求める
    static long DeriveBekijyou(long pN, long pP, long pM)
    {
        long CurrJyousuu = pN % pM;
        long CurrShisuu = 1;
        long WillReturn = 1;

        while (true) {
            // 対象ビットが立っている場合
            if ((pP & CurrShisuu) > 0) {
                WillReturn = (WillReturn * CurrJyousuu) % pM;
            }

            CurrShisuu *= 2;
            if (CurrShisuu > pP) return WillReturn;
            CurrJyousuu = (CurrJyousuu * CurrJyousuu) % pM;
        }
    }
}


解説

mod 1000000007の世界での、0は扱いが特殊なので
0を含む解を、最初に計上してます。