AtCoderの企業コンテスト
次の企業コンテストの問題へ
前の企業コンテストの問題へ
第一回日本最強プログラマー学生選手権 予選 B Kleene Inversion
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("2 2");
WillReturn.Add("2 1");
//3
}
else if (InputPattern == "Input2") {
WillReturn.Add("3 5");
WillReturn.Add("1 1 1");
//0
}
else if (InputPattern == "Input3") {
WillReturn.Add("10 998244353");
WillReturn.Add("10 9 8 7 5 6 3 4 2 1");
//185297239
}
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 Answer = 0;
long HantenCntInner = DeriveHantenCntInner(AArr);
long HantenCntOuter = DeriveHantenCntOuter(AArr);
Answer += HantenCntInner * K;
Answer %= Hou;
long Choose = DeriveChoose(K, 2);
long OuterCnt = Choose * HantenCntOuter;
OuterCnt %= Hou;
Answer += OuterCnt;
Answer %= Hou;
Console.WriteLine(Answer);
}
// 配列を引数として、配列内の反転数の個数を返す
static long DeriveHantenCntInner(long[] pArr)
{
long HantenCnt = 0;
for (int I = 0; I <= pArr.GetUpperBound(0); I++) {
for (int J = 0; J <= I - 1; J++) {
if (pArr[J] > pArr[I]) {
HantenCnt++;
}
HantenCnt %= Hou;
}
}
return HantenCnt;
}
// 配列を引数として、同じ配列2つの間での反転数の個数を返す
static long DeriveHantenCntOuter(long[] pArr)
{
long HantenCnt = 0;
for (int I = 0; I <= pArr.GetUpperBound(0); I++) {
HantenCnt += pArr.Count(pX => pX < pArr[I]);
HantenCnt %= Hou;
}
return HantenCnt;
}
// nCr (mod Hou)を求める
static long DeriveChoose(long pN, long pR)
{
if (pN < pR) return 0;
pR = Math.Min(pR, pN - pR);
long WillReturn = 1;
for (long I = pN - pR + 1; I <= pN; I++) {
WillReturn *= I;
WillReturn %= Hou;
}
for (long I = 2; I <= pR; I++) {
WillReturn *= DeriveGyakugen(I);
WillReturn %= Hou;
}
return WillReturn;
}
// 引数の逆元を求める
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;
}
}
}
解説
1 9 7 3 5
という配列を3回繰り返すとして、考察します。
配列内部の反転数は、2重ループや、マージソートなどで求めることができます。
配列から他の配列を見たときの反転数は、2つの配列のペアで求めておき、
N個から2個選ぶ組み合わせの場合の数を、掛け算すれば分かります。