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 4 2");
WillReturn.Add("1 7 7 9");
WillReturn.Add("9 6 3 7");
WillReturn.Add("7 8 6 4");
//10
}
else if (InputPattern == "Input2") {
WillReturn.Add("3 3 1000000000");
WillReturn.Add("1000000 1000000 1");
WillReturn.Add("1000000 1000000 1000000");
WillReturn.Add("1 1000000 1000000");
//1001000001
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static long mC;
static void Main()
{
List<string> InputList = GetInputList();
long[] wkArr = InputList[0].Split(' ').Select(pX => long.Parse(pX)).ToArray();
mC = wkArr[2];
long[,] BanArr1 = CreateBanArr(InputList.Skip(1));
long[,] BanArr2 = Kaiten90do(BanArr1);
long[,] BanArr3 = Kaiten90do(BanArr2);
long[,] BanArr4 = Kaiten90do(BanArr3);
var DPResultList = new List<long>();
DPResultList.Add(ExecDP(BanArr1));
DPResultList.Add(ExecDP(BanArr2));
DPResultList.Add(ExecDP(BanArr3));
DPResultList.Add(ExecDP(BanArr4));
Console.WriteLine(DPResultList.Min());
}
// 盤面を引数として、DPを行う
static long ExecDP(long[,] pBanArr)
{
int UB_X = pBanArr.GetUpperBound(0);
int UB_Y = pBanArr.GetUpperBound(1);
// 最小コスト[X,Y,選択数]なDP表
long?[, ,] DPArr = new long?[UB_X + 1, UB_Y + 1, 3];
// 初期化しておく
for (int LoopX = 0; LoopX <= UB_X; LoopX++) {
for (int LoopY = 0; LoopY <= UB_Y; LoopY++) {
DPArr[LoopX, LoopY, 0] = 0;
}
}
for (int LoopX = 0; LoopX <= UB_X; LoopX++) {
for (int LoopY = 0; LoopY <= UB_Y; LoopY++) {
for (int LoopK = 1; 0 <= LoopK; LoopK--) {
Action<int, int, int, long> UpsertAct = (pNewX, pNewY, pNewK, pNewVal) =>
{
if (pNewX < 0 || UB_X < pNewX) return;
if (pNewY < 0 || UB_Y < pNewY) return;
if (DPArr[pNewX, pNewY, pNewK].HasValue) {
if (DPArr[pNewX, pNewY, pNewK] <= pNewVal) {
return;
}
}
DPArr[pNewX, pNewY, pNewK] = pNewVal;
};
if (DPArr[LoopX, LoopY, LoopK].HasValue == false) {
continue;
}
int NewK = LoopK + 1;
long NewVal;
if (NewK == 1) {
NewVal = -mC * (LoopX + LoopY) + pBanArr[LoopX, LoopY];
}
else {
NewVal = DPArr[LoopX, LoopY, 1].Value +
mC * (LoopX + LoopY) + pBanArr[LoopX, LoopY];
}
UpsertAct(LoopX, LoopY, NewK, NewVal);
long KakuteiVal = DPArr[LoopX, LoopY, NewK].Value;
// 確定したカレントの値を配る
UpsertAct(LoopX, LoopY + 1, NewK, KakuteiVal);
UpsertAct(LoopX + 1, LoopY, NewK, KakuteiVal);
}
}
}
long DPResult = long.MaxValue;
for (int LoopX = 0; LoopX <= UB_X; LoopX++) {
for (int LoopY = 0; LoopY <= UB_Y; LoopY++) {
if (DPArr[LoopX, LoopY, 2].HasValue) {
DPResult = Math.Min(DPResult, DPArr[LoopX, LoopY, 2].Value);
}
}
}
return DPResult;
}
// 右に90度回転させた盤面を返す
static Type[,] Kaiten90do<Type>(Type[,] pBanArr)
{
Type[,] WillReturn = new Type[pBanArr.GetUpperBound(1) + 1,
pBanArr.GetUpperBound(0) + 1];
for (int X = 0; X <= WillReturn.GetUpperBound(0); X++) {
for (int Y = 0; Y <= WillReturn.GetUpperBound(1); Y++) {
WillReturn[X, Y] = pBanArr[Y, WillReturn.GetUpperBound(0) - X];
}
}
return WillReturn;
}
////////////////////////////////////////////////////////////////
// IEnumerable<string>をintの2次元配列に設定する
////////////////////////////////////////////////////////////////
static long[,] CreateBanArr(IEnumerable<string> pStrEnum)
{
var StrList = pStrEnum.ToList();
if (StrList.Count == 0) {
return new long[0, 0];
}
long[] IntArr = { };
Action<string> SplitAct = pStr =>
IntArr = pStr.Split(' ').Select(pX => long.Parse(pX)).ToArray();
SplitAct(StrList[0]);
int UB_X = IntArr.GetUpperBound(0);
int UB_Y = StrList.Count - 1;
long[,] WillReturn = new long[UB_X + 1, UB_Y + 1];
for (int Y = 0; Y <= UB_Y; Y++) {
SplitAct(StrList[Y]);
for (int X = 0; X <= UB_X; X++) {
WillReturn[X, Y] = IntArr[X];
}
}
return WillReturn;
}
}