#include "bits/stdc++.h"

using namespace std;
#ifdef _DEBUG
#define _GLIBCXX_DEBUG
#include "dump.hpp"
#else
#define dump(...)
#endif

#define int long long
#define ll long long
#define DBG 1
#define rep(i, a, b) for (int i = (a); i < (b); i++)
#define rrep(i, a, b) for (int i = (b)-1; i >= (a); i--)
#define loop(n) rep(loop, (0), (n))
#define all(c) begin(c), end(c)
const int INF = sizeof(int) == sizeof(long long) ? 0x3f3f3f3f3f3f3f3fLL : 0x3f3f3f3f;
const int MOD = (int)(1e9) + 7;
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
using pii = pair<int, int>;
// template<class T> ostream &operator<<(ostream &os,T &t){dump(t);return os;}
template <typename T, typename S>istream &operator>>(istream &is, pair<T, S> &p) { is >> p.first >> p.second; return is; }
//template <typename T, typename S>ostream &operator<<(ostream &os, pair<T, S> &p) {os << p.first << " " << p.second;return os;}

template <typename T> void printvv(const vector<vector<T>> &v) {
	cerr << endl;
	rep(i, 0, v.size()) rep(j, 0, v[i].size()) {
		if (typeid(v[i][j]).name() == typeid(INF).name() and v[i][j] == INF) {
			cerr << "INF";
		}
		else
			cerr << v[i][j];
		cerr << (j == v[i].size() - 1 ? '\n' : ' ');
	}
	cerr << endl;
}

#ifndef _DEBUG
#define printvv(...)
#endif
void YES(bool f) { cout << (f ? "YES" : "NO") << endl; }
void Yes(bool f) { cout << (f ? "Yes" : "No") << endl; }
template <class T, class U>bool chmin(T& a, U b) { if (a > b) { a = b; return true; }return false; }
template <class T, class U>bool chmax(T& a, U b) { if (a < b) { a = b; return true; }return false; }
template< typename Monoid, typename OperatorMonoid, typename F, typename G, typename H>
struct LazySegmentTree {

	int sz, height;
	vector< Monoid > data;
	vector< OperatorMonoid > lazy;
	const F f;
	const G g;
	const H h;
	const Monoid M1;
	const OperatorMonoid OM0;


	LazySegmentTree(int n, const F f, const G g, const H h,
		const Monoid &M1, const OperatorMonoid OM0)
		: f(f), g(g), h(h), M1(M1), OM0(OM0) {
		sz = 1;
		height = 0;
		while (sz < n) sz <<= 1, height++;
		data.assign(2 * sz, M1);
		lazy.assign(2 * sz, OM0);
	}

	void set(int k, const Monoid &x) {
		data[k + sz] = x;
	}

	void build() {
		for (int k = sz - 1; k > 0; k--) {
			data[k] = f(data[2 * k + 0], data[2 * k + 1]);
		}
	}

	inline void propagate(int k) {
		if (lazy[k] != OM0) {
			lazy[2 * k + 0] = h(lazy[2 * k + 0], lazy[k]);
			lazy[2 * k + 1] = h(lazy[2 * k + 1], lazy[k]);
			data[k] = reflect(k);
			lazy[k] = OM0;
		}
	}

	inline Monoid reflect(int k) {
		return lazy[k] == OM0 ? data[k] : g(data[k], lazy[k]);
	}

	inline void recalc(int k) {
		while (k >>= 1) data[k] = f(reflect(2 * k + 0), reflect(2 * k + 1));
	}

	inline void thrust(int k) {
		for (int i = height; i > 0; i--) propagate(k >> i);
	}

	void update(int a, int b, const OperatorMonoid &x) {
		thrust(a += sz);
		thrust(b += sz - 1);
		for (int l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
			if (l & 1) lazy[l] = h(lazy[l], x), ++l;
			if (r & 1) --r, lazy[r] = h(lazy[r], x);
		}
		recalc(a);
		recalc(b);
	}

	Monoid query(int a, int b) {
		thrust(a += sz);
		thrust(b += sz - 1);
		Monoid L = M1, R = M1;
		for (int l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
			if (l & 1) L = f(L, reflect(l++));
			if (r & 1) R = f(reflect(--r), R);
		}
		return f(L, R);
	}

	Monoid operator[](const int &k) {
		return query(k, k + 1);
	}

	template< typename C >
	int find_subtree(int a, const C &check, Monoid &M, bool type) {
		while (a < sz) {
			propagate(a);
			Monoid nxt = type ? f(reflect(2 * a + type), M) : f(M, reflect(2 * a + type));
			if (check(nxt)) a = 2 * a + type;
			else M = nxt, a = 2 * a + 1 - type;
		}
		return a - sz;
	}

	template< typename C >
	int find_first(int a, const C &check) {
		Monoid L = M1;
		if (a <= 0) {
			if (check(f(L, reflect(1)))) return find_subtree(1, check, L, false);
			return -1;
		}
		thrust(a + sz);
		int b = sz;
		for (a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
			if (a & 1) {
				Monoid nxt = f(L, reflect(a));
				if (check(nxt)) return find_subtree(a, check, L, false);
				L = nxt;
				++a;
			}
		}
		return -1;
	}


	template< typename C >
	int find_last(int b, const C &check) {
		Monoid R = M1;
		if (b >= sz) {
			if (check(f(reflect(1), R))) return find_subtree(1, check, R, true);
			return -1;
		}
		thrust(b + sz - 1);
		int a = sz;
		for (b += sz; a < b; a >>= 1, b >>= 1) {
			if (b & 1) {
				Monoid nxt = f(reflect(--b), R);
				if (check(nxt)) return find_subtree(b, check, R, true);
				R = nxt;
			}
		}
		return -1;
	}
};


signed main(signed argc, char *argv[]) {
	cin.tie(0);
	ios::sync_with_stdio(false);
	cout << fixed << setprecision(12);

	auto f = [](int a, int b) {return min(a, b); };
	auto g = [](int a, int b) {return a + b; };
	auto h = [](int a, int b) {return a + b; };
	int ti = numeric_limits<int>::max();
	int ei = 0;


	int N; cin >> N;
	int D; cin >> D;
	int A; cin >> A;


	vector<int>X(N), H(N); rep(i, 0, N) { cin >> X[i] >> H[i]; }
	vector<pii>monster;
	rep(i, 0, N) {
		monster.eb(X[i], H[i]);
	}
	sort(all(monster));

	LazySegmentTree<int, int, decltype(f), decltype(g), decltype(h)>seg(N, f, g, h, ti, ei);
	rep(i, 0, N) {
		seg.set(i, monster[i].second);
	}
	seg.build();
	auto calc = [&](int t) {
		vector<int>v(N + 1);
		int cnt = 0;
		int r = 0;
		rep(i, 0, N) {
			while (r < N and abs(monster[i].first - monster[r].first) <= 2 * D) {
				r++;
			}
			if (monster[i].second + v[i] > 0) {
				int x = (monster[i].second + v[i] + A - 1) / A;
				v[i] += -A * x;
				v[r] += A * x;
				cnt += x;
			}
			v[i + 1] += v[i];
			if (cnt > t)return false;
		}
		return cnt <= t;
	};

	int l = 0, r = 1e15;
	while (r - l > 1) {
		int m = (l + r) / 2;
		if (calc(m)) {
			r = m;
		}
		else {
			l = m;
		}
	}
	cout << r << endl;



	return 0;
}


Measured memory_bytes: 17132