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

ABC125-D Flipping Signs


問題へのリンク


C#のソース(DP)

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("3");
            WillReturn.Add("-10 5 -4");
            //19
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("5");
            WillReturn.Add("10 -4 -8 -11 3");
            //30
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("11");
            WillReturn.Add("-1000000000 1000000000 -1000000000 1000000000 -1000000000 0 1000000000 -1000000000 1000000000 -1000000000 1000000000");
            //10000000000
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

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

        // 和の最大値[符号反転済みか]
        long?[] PrevDP = new long?[2];
        PrevDP[0] = AArr[0];
        PrevDP[1] = -AArr[0];

        for (long I = 1; I <= UB - 1; I++) {
            long?[] CurrDP = new long?[2];

            for (long J = 0; J <= 1; J++) {
                if (PrevDP[J].HasValue == false) continue;

                Action<long, long> SendAct = (pNewJ, pNewVal) =>
                {
                    if (CurrDP[pNewJ].HasValue) {
                        if (CurrDP[pNewJ] >= pNewVal) {
                            return;
                        }
                    }
                    CurrDP[pNewJ] = pNewVal;
                };

                // 反転させない場合
                SendAct(J, PrevDP[J].Value + AArr[I]);

                // 反転する場合
                long NewJ = (J + 1) % 2;
                SendAct(NewJ, PrevDP[J].Value - AArr[I]);
            }
            PrevDP = CurrDP;
        }

        var AnswerKouho = new List<long>();
        AnswerKouho.Add(PrevDP[0].Value + AArr[UB]);
        AnswerKouho.Add(PrevDP[1].Value - AArr[UB]);
        Console.WriteLine(AnswerKouho.Max());
    }
}


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>();
        string wkStr;
        while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        return WillReturn;
    }

    static void Main()
    {
        List<string> InputList = GetInputList();

        int[] AArr = InputList[1].Split(' ').Select(X => int.Parse(X)).ToArray();

        // 負数の数
        int MinusCnt = AArr.Count(X => X < 0);

        // 絶対値の最小値
        int MinABS = AArr.Min(X => Math.Abs(X));

        long SumABS = 0;
        Array.ForEach(AArr, X => SumABS += Math.Abs(X));

        // 負数が偶数個の場合
        if (MinusCnt % 2 == 0) {
            Console.WriteLine(SumABS);
        }
        else { // 負数が奇数個の場合
            Console.WriteLine(SumABS - MinABS * 2);
        }
    }
}


解説

和の最大値[符号反転済みか]
を更新するDPで解くことができますが、

マイナスの数の不変量に着目すると
mod 2 の世界で不変なので、
これを使って解くこともできます。