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

A76 River Crossing


問題へのリンク


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("5 65 7 37");
            WillReturn.Add("5 15 30 50 55");
            //7
        }
        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 W = wkArr[1];
        long L = wkArr[2];
        long R = wkArr[3];

        var XList = new List<long>();
        XList.Add(0);
        XList.AddRange(InputList[1].Split(' ').Select(pX => long.Parse(pX)));
        XList.Add(W);

        long[] XArr = XList.ToArray();
        long UB = XArr.GetUpperBound(0);

        // 場合の数[現在添字]なDP表
        long[] DPArr = new long[UB + 1];
        DPArr[0] = 1;

        long[] ImosArr = new long[UB + 1];

        for (long I = 0; I <= UB; I++) {
            if (I > 0) {
                ImosArr[I] += ImosArr[I - 1];
                ImosArr[I] %= Hou;
            }
            DPArr[I] += ImosArr[I];
            DPArr[I] %= Hou;

            if (DPArr[I] == 0) continue;

            long RangeL = XArr[I] + L;
            long RangeR = XArr[I] + R;

            int ResultInd1 = ExecNibunhou_LowerBound(RangeL, XArr);
            if (ResultInd1 == -1) continue;

            int ResultInd2 = ExecNibunhou_LowerOrEqual_Max(RangeR, XArr);
            if (ResultInd2 == -1) continue;

            if (ResultInd1 <= ResultInd2) {
                int ImosSta = ResultInd1;
                int ImosEnd = ResultInd2 + 1;

                ImosArr[ImosSta] += DPArr[I];
                ImosArr[ImosSta] %= Hou;
                if (ImosEnd <= UB) {
                    ImosArr[ImosEnd] -= DPArr[I];
                    if (ImosArr[ImosEnd] < 0) {
                        ImosArr[ImosEnd] += Hou;
                    }
                    ImosArr[ImosEnd] %= Hou;
                }
            }
        }
        Console.WriteLine(DPArr[UB]);
    }

    // 二分法で、Val以上で最小の値を持つ、添字を返す
    static int ExecNibunhou_LowerBound(long pVal, long[] pArr)
    {
        // 最後の要素がVal未満の特殊ケース
        if (pVal > pArr.Last()) {
            return -1;
        }
        // 最初の要素がVal以上の特殊ケース
        if (pVal <= pArr[0]) {
            return 0;
        }

        int L = 0;
        int R = pArr.GetUpperBound(0);

        while (L + 1 < R) {
            int Mid = (L + R) / 2;

            if (pArr[Mid] >= pVal) {
                R = Mid;
            }
            else {
                L = Mid;
            }
        }
        return R;
    }

    // 二分法で、Val以下で最大の値を持つ、添字を返す
    static int ExecNibunhou_LowerOrEqual_Max(long pVal, long[] pArr)
    {
        // 最後の要素がVal以下の特殊ケース
        if (pVal >= pArr.Last()) {
            return pArr.GetUpperBound(0);
        }
        // 最初の要素がVal超えの特殊ケース
        if (pVal < pArr[0]) {
            return -1;
        }

        int L = 0;
        int R = pArr.GetUpperBound(0);

        while (L + 1 < R) {
            int Mid = (L + R) / 2;

            if (pArr[Mid] <= pVal) {
                L = Mid;
            }
            else {
                R = Mid;
            }
        }
        return L;
    }
}


解説

配るDPですが、いもす法で配ってます。