AtCoderのABC    次のABCの問題へ    前のABCの問題へ

ABC027-D ロボット


問題へのリンク


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("M+MM-M");
            //2
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("MMM+M");
            //1
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("MMM+--MMM");
            //3
        }
        else if (InputPattern == "Input4") {
            WillReturn.Add("+");
            //0
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    struct RestInfoDef
    {
        internal int RestMinusCnt;
        internal int RestPlusCnt;
    }

    static void Main()
    {
        List<string> InputList = GetInputList();
        string S = InputList[0];

        // 以降の件数[現在座標]なDict
        var RestInfoDict = new Dictionary<int, RestInfoDef>();
        int MinusCnt = 0;
        int PlusCnt = 0;
        int MoveCnt = 0;
        for (int I = S.Length - 1; 0 <= I; I--) {
            if (S[I] == '-') MinusCnt++;
            if (S[I] == '+') PlusCnt++;

            if (S[I] == 'M') {
                MoveCnt++;
                RestInfoDef WillAdd;
                WillAdd.RestMinusCnt = MinusCnt;
                WillAdd.RestPlusCnt = PlusCnt;
                RestInfoDict[I] = WillAdd;
            }
        }

        // +に移動した時の御得度の降順でソート
        var MovePlusIndSet = new HashSet<int>();
        var Query = RestInfoDict.OrderByDescending(pX => pX.Value.RestPlusCnt - pX.Value.RestMinusCnt);
        foreach (var RestInfoDef in Query.Take(MoveCnt / 2)) {
            MovePlusIndSet.Add(RestInfoDef.Key);
        }

        int CurrPos = 0;
        int Answer = 0;
        for (int I = 0; I <= S.Length - 1; I++) {
            if (S[I] == 'M') {
                if (MovePlusIndSet.Contains(I)) {
                    CurrPos++;
                }
                else {
                    CurrPos--;
                }
            }
            if (S[I] == '+') {
                Answer += CurrPos;
            }
            if (S[I] == '-') {
                Answer -= CurrPos;
            }
        }
        Console.WriteLine(Answer);
    }
}


解説

最大スコア[現在位置]でDPすると
O(状態数の2乗)でTLEになるので
アドホックに解きます。

考察すると、
最後に原点に戻らなければならないので、
例えば、Mの個数が10個だと
1増やす移動が5回
1減らす移動が5回
になります。

1増やす移動の得と、
1減らす移動の得は、
ゼロサムゲームなので

1増やす移動での最終スコアの増加の降順で
5箇所が1増やす移動の箇所。
これ以外の5箇所が
1減らす移動の箇所になります。