AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC151-E Max-Min Sums
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 2");
WillReturn.Add("1 1 3 4");
//11
}
else if (InputPattern == "Input2") {
WillReturn.Add("6 3");
WillReturn.Add("10 10 10 -10 -10 -10");
//360
}
else if (InputPattern == "Input3") {
WillReturn.Add("3 1");
WillReturn.Add("1 1 1");
//0
}
else if (InputPattern == "Input4") {
WillReturn.Add("10 6");
WillReturn.Add("1000000000 1000000000 1000000000 1000000000 1000000000 0 0 0 0 0");
//999998537
}
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 K = wkArr[1];
long[] AArr = InputList[1].Split(' ').Select(pX => long.Parse(pX)).ToArray();
long UB = AArr.GetUpperBound(0);
if (AArr.Length == 1) {
Console.WriteLine(0);
return;
}
long Answer = 0;
ChooseMod InsChooseMod = new ChooseMod(AArr.Length, Hou);
// 昇順にソート
Array.Sort(AArr);
// 最小値ごとに場合の数との積を解に加算
for (long I = 0; I <= UB; I++) {
// カレントの最小値
long CurrMin = AArr[I];
long nC = AArr.Length - (I + 1);
long Cr = K - 1;
if (nC < Cr) break;
long PatternCnt = InsChooseMod.DeriveChoose(nC, Cr);
Answer += PatternCnt * (-CurrMin);
Answer %= Hou;
}
// 降順にソート
Array.Sort(AArr, (pA, pB) => pB.CompareTo(pA));
// 最大値ごとに場合の数との積を解に加算
for (long I = 0; I <= UB; I++) {
// カレントの最大値
long CurrMax = AArr[I];
long nC = AArr.Length - (I + 1);
long Cr = K - 1;
if (nC < Cr) break;
long PatternCnt = InsChooseMod.DeriveChoose(nC, Cr);
Answer += PatternCnt * CurrMax;
Answer %= Hou;
}
if (Answer < 0) Answer += Hou;
Console.WriteLine(Answer);
}
}
#region ChooseMod
// 二項係数クラス
internal class ChooseMod
{
private long mHou;
private long[] mFacArr;
private long[] mFacInvArr;
private long[] mInvArr;
// コンストラクタ
internal ChooseMod(long pCnt, long pHou)
{
mHou = pHou;
mFacArr = new long[pCnt + 1];
mFacInvArr = new long[pCnt + 1];
mInvArr = new long[pCnt + 1];
mFacArr[0] = mFacArr[1] = 1;
mFacInvArr[0] = mFacInvArr[1] = 1;
mInvArr[1] = 1;
for (int I = 2; I <= pCnt; I++) {
mFacArr[I] = mFacArr[I - 1] * I % mHou;
mInvArr[I] = mHou - mInvArr[mHou % I] * (mHou / I) % mHou;
mFacInvArr[I] = mFacInvArr[I - 1] * mInvArr[I] % mHou;
}
}
// nCrを返す
internal long DeriveChoose(long pN, long pR)
{
if (pN < pR) return 0;
if (pN < 0 || pR < 0) return 0;
return mFacArr[pN] * (mFacInvArr[pR] * mFacInvArr[pN - pR] % mHou) % mHou;
}
}
#endregion
解説
10 20 30 40 50 60 70 80
から6個選ぶ数列で考えます。
10を最小値に持つ選び方は、7C5通り
20を最小値に持つ選び方は、6C5通り
30を最小値に持つ選び方は、5C5通り
なので、解に
(-10 * 7C5) + (-20 * 6C5) + (-30 * 5C5)
を計上します。
最大値については、配列を逆順にソートして
80 70 60 50 40 30 20 10
から6個選ぶ数列で考えます。
80を最大値に持つ選び方は、7C5通り
70を最大値に持つ選び方は、6C5通り
60を最大値に持つ選び方は、5C5通り
なので、解に
(80 * 7C5) + (70 * 6C5) + (60 * 5C5)
を計上します。
これらを実装すれば解くことができます。