#include <bits/stdc++.h>
using namespace std;
template <class T> inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <class T> inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return 1;
    }
    return 0;
}
typedef long long int ll;

#define ALL(v) (v).begin(), (v).end()
#define RALL(v) (v).rbegin(), (v).rend()
#define endl "\n"
const double EPS = 1e-7;
const int INF = 1 << 30;
const ll LLINF = 1LL << 60;
const double PI = acos(-1);
const int MOD = 1000000007;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

//-------------------------------------

struct LazyRSQ {
  private:
    ll n;
    vector<ll> node, lazy;

  public:
    LazyRSQ(vector<ll> v) {
        ll sz = (ll)v.size();
        n = 1;
        while(n < sz) {
            n *= 2;
        }
        node.resize(2 * n - 1);
        lazy.resize(2 * n - 1, 0);
        for(ll i = 0; i < sz; i++) {
            node[i + n - 1] = v[i];
        }
        for(ll i = n - 2; i >= 0; i--) {
            node[i] = node[2 * i + 1] + node[2 * i + 2];
        }
    }
    // k番目のnodeについて遅延評価を行う
    void eval(ll k, ll l, ll r) {
        // 遅延配列が空でない場合、自nodeと子nodeへの値の伝播が起こる
        if(lazy[k] != 0) {
            node[k] += lazy[k];
        }
        // 最下段かどうかのチェック
        // 伝播させるときは半分にする
        if(r - l > 1) {
            lazy[2 * k + 1] += lazy[k] / 2;
            lazy[2 * k + 2] += lazy[k] / 2;
        }
        // 伝播が終わったら自nodeの遅延配列を0に戻す
        lazy[k] = 0;
    }

    // 区間[a,b)に対してxを加算するクエリの処理
    void add(ll a, ll b, ll x, ll now = 0, ll l = 0, ll r = -1) {
        if(r < 0) {
            r = n;
        }
        // now番目のnodeに対して遅延評価
        eval(now, l, r);
        // 範囲外のとき
        if(b <= l || r <= a) {
            return;
        }
        if(a <= l && r <= b) {
            // 完全に区間を覆っている時
            lazy[now] += (r - l) * x;
            eval(now, l, r);
        } else {
            // そうでないとき
            // 子ノードの値を計算してから自分のノードを更新
            add(a, b, x, 2 * now + 1, l, (l + r) / 2);
            add(a, b, x, 2 * now + 2, (l + r) / 2, r);
            node[now] = node[2 * now + 1] + node[2 * now + 2];
        }
    }

    // 区間[a,b)の和を求めるクエリを処理
    ll getsum(ll a, ll b, ll now = 0, ll l = 0, ll r = -1) {
        if(r < 0) {
            r = n;
        }
        if(b <= l || r <= a) {
            return 0;
        }
        eval(now, l, r);
        if(a <= l && r <= b) {
            return node[now];
        }
        ll vl = getsum(a, b, 2 * now + 1, l, (l + r) / 2);
        ll vr = getsum(a, b, 2 * now + 2, (l + r) / 2, r);
        return vl + vr;
    }
};

using P = pair<ll, ll>;

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);

    ll n, d, a;
    cin >> n >> d >> a;
    vector<P> mons(n);
    for(ll i = 0; i < n; i++) {
        cin >> mons[i].first >> mons[i].second;
        mons[i].second = (mons[i].second + a - 1) / a;
        // cout << "dbg:" << mons[i].second << endl;
    }
    sort(ALL(mons));
    vector<ll> v(n);
    for(ll i = 0; i < n; i++) {
        v[i] = mons[i].second;
    }
    LazyRSQ seg(v);
    ll ans = 0;
    // cout << "dbg: ";
    // for(ll j = 0; j < n; j++) {
    //     cout << seg.getsum(j, j + 1) << " ";
    // }
    // cout << endl;
    for(ll i = 0; i < n; i++) {
        ll need = seg.getsum(i, i + 1);
        if(need <= 0) {
            continue;
        }
        auto it = upper_bound(ALL(mons), P(mons[i].first + 2 * d, LLINF));
        // if(it != mons.begin()) {
        //     it--;
        // }
        ll id = it - mons.begin();
        seg.add(i, id, -need);
        // cout << "id: " << id << endl;
        // cout << "dbg: ";
        // for(ll j = 0; j < n; j++) {
        //     cout << seg.getsum(j, j + 1) << " ";
        // }
        // cout << endl;
        ans += need;
    }
    cout << ans << endl;
}

Measured memory_bytes: 14720