#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int ll

#define REP(i,n) for(int i=0;i<n;++i)
#define SORT(name) sort(name.begin(), name.end())
#define ZERO(p) memset(p, 0, sizeof(p))
#define MINUS(p) memset(p, -1, sizeof(p))
#if 1
#  define DBG(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#  define DBG(fmt, ...)
#endif

const ll LLINF = (1LL<<60);
const int INF = (1LL<<30);
const double DINF = std::numeric_limits<double>::infinity();
const int MOD = 1000000007;
#define MAX_N 100010

class UnionFind {
    public:
        UnionFind(int size) { m_Data.assign(size, -1); }
        bool Unite(int x, int y) {
            x = Find(x), y = Find(y);
            if(x == y) { return (false); }
            if(m_Data[x] > m_Data[y]) { swap(x, y); }
            m_Data[x] += m_Data[y];
            m_Data[y] = x;
            return (true);
        }
        int Find(int k) {
            if(m_Data[k] < 0) { return (k); }
            return (m_Data[k] = Find(m_Data[k]));
        }
        int Size(int k) { return (-m_Data[Find(k)]); }
    private:
        vector<int> m_Data;
};

// ※要 UnionFind
// T : コストの型
template<typename T>
class Kruskal {
    public:
        // 辺を表す構造体
        struct Edge {
            int src, to;  // src: 指し元, to: 指し先
            T cost;       // 辺のコスト
            Edge(int to, T cost) : src(-1), to(to), cost(cost) {}
            Edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}
            Edge &operator=(const int &x) {
                to = x;
                return *this;
            }
            operator int() const { return to; }
        };
    public:
        Kruskal() {}
        Kruskal(int v) { Init(v); }
        void Init(int v) { m_V = v; }
        // 有向辺の追加
        void AddDEdge(int from, int to, T cost) {
            m_Edges.push_back(Edge(from, to, cost));
        }
        // 無向辺の追加
        void AddUdEdge(int from, int to, int cost) {
            m_Edges.push_back(Edge(from, to, cost));
            m_Edges.push_back(Edge(to, from, cost));
        }
        // 全域木の最小コストを返す
        T GetCost() {
            sort(begin(m_Edges), end(m_Edges), [](const Edge &a, const Edge &b) {
                    return (a.cost < b.cost);
                    });
            UnionFind tree(m_V);
            T ret = 0;
            for(auto &e : m_Edges) { if(tree.Unite(e.src, e.to)) { ret += e.cost; } }
            return (ret);
        }
    private:
        int m_V;                // 頂点数
        vector<Edge> m_Edges;   // 辺集合
};

ll N, D;
vector<ll> A;

Kruskal<ll> kr;

// A の [l, r] の範囲を半分で分割し、
// 左から見た場合の適切な右ノードと
// 右から見た場合の適切な左ノードを辺で接続する。
// 以上を再帰的に繰り返す
void dfs(ll l, ll r) {
    if(r - l <= 0) { return; }
    // 領域を [l, mid], [mid+1, r] の 2 つに分割
    ll mid = (r - l) / 2 + l;

    // 右側の最適な頂点を求める
    ll r_min = -1;
    for(ll i = mid + 1; i <= r; ++i) {
        if(r_min < 0 || D * i + A[i] < D * r_min + A[r_min]) { r_min = i; }
    }
    // 左側の最適な頂点を求める
    ll l_min = -1;
    for(ll i = l; i <= mid; ++i) {
        if(l_min < 0 || D * (mid - i) + A[i] < D * (mid - l_min) + A[l_min]) { l_min = i; }
    }

    // 左の各頂点から右の最適な頂点に辺を張る
    for(ll i = l; i <= mid; ++i) {
        kr.AddUdEdge(i, r_min, D * abs(i - r_min) + A[i] + A[r_min]);
    }
    // 右の各頂点から左の最適な頂点に辺を張る
    for(ll i = mid + 1; i <= r; ++i) {
        kr.AddUdEdge(i, l_min, D * abs(i - l_min) + A[i] + A[l_min]);
    }
    dfs(l, mid);
    dfs(mid + 1, r);
}

// 分割統治クラスカルで解く
ll solve() {
    kr.Init(N);
    dfs(0, N-1);
    return kr.GetCost();
}

signed main()
{
    cin >> N >> D;
    A.resize(N);
    REP(i, N) { cin >> A[i]; }
    ll ans = solve();
    printf("%lld\n", ans);
    return 0;
}


Measured memory_bytes: 200540