Problem:
Score : 600 points

Problem Statement

Silver Fox is fighting with N monsters.

The monsters are standing in a row, and we can assume them to be standing on a number line. The i-th monster, standing at the coordinate X_i, has the health of H_i.

Silver Fox can use bombs to attack the monsters.
Using a bomb at the coordinate x decreases the healths of all monsters between the coordinates x-D and x+D (inclusive) by A.
There is no way other than bombs to decrease the monster's health.

Silver Fox wins when all the monsters' healths become 0 or below.

Find the minimum number of bombs needed to win.

Constraints

1 \leq N \leq 2 \times 10^5

0 \leq D \leq 10^9

1 \leq A \leq 10^9

0 \leq X_i \leq 10^9

1 \leq H_i \leq 10^9

X_i are distinct.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N D A
X_1 H_1
:
X_N H_N

Output

Print the minimum number of bombs needed to win.

Sample Input 1

3 3 2
1 2
5 4
9 2

Sample Output 1

2

First, let us use a bomb at the coordinate 4 to decrease the first and second monsters' health by 2.

Then, use a bomb at the coordinate 6 to decrease the second and third monsters' health by 2.

Now, all the monsters' healths are 0.
We cannot make all the monsters' health drop to 0 or below with just one bomb.

Sample Input 2

9 4 1
1 5
2 4
3 3
4 2
5 1
6 2
7 3
8 4
9 5

Sample Output 2

5

We should use five bombs at the coordinate 5.

Sample Input 3

3 0 1
300000000 1000000000
100000000 1000000000
200000000 1000000000

Sample Output 3

3000000000

Watch out for overflow.

Solution in C++14 (GCC 5.4.1) (judge verdict: Time Limit Exceeded)

#include <bits/stdc++.h>
//#include <mylib.h>
using namespace std;
//cin.sync_with_stdio(false);

#define FOR(i,a,b) for(ll i = (a); i < (b); ++i)
#define FOR_EQ(i,a,b) for(ll i = (a); i <= (b); ++i)
#define FOR_RE(i,a,b) for(ll i = (a)-1; i >= (b); --i)
// FOR_RE(i, n, n - m)  nからm回分
#define rep(i,n) FOR(i,0,n)
#define rep_eq(i,n) FOR_EQ(i,0,n)
#define rep_re(i,n) FOR_RE(i,n,0)

#define DEBUG_VARIABLE(variable) cout << #variable << ":" << variable << endl

#define INFTY 1000000000000

#define WHITE 1//（未訪問）
#define GRAY 2//（訪問）未だに訪問していない頂点への辺を持っている。スタックに退避。
#define BLACK 3//（訪問完了）未訪問への頂点への辺を持たない
/*
int M[N][N];// 隣接行列(頂点と頂点が繋がってる、もしくは重みの値)
int color[N]; // その頂点の探索具合
*/
const int TABLEMAX = 510000;
const int MOD = 1000000007;
//二項係数用の各階乗の値とその逆元を記録するための配列．
int fac[TABLEMAX];
int finv[TABLEMAX / 2], inv[TABLEMAX / 2];

/*
//1個上から時計周り
const int ddx[8] = {0, 1, 1, 1, 0, -1, -1, -1};
const int ddy[8] = {1, 1, 0, -1, -1, -1, 0, 1};
//上右下左
const int dx[4] = {0, 1, 0, -1};    // dj
const int dy[4] = {-1, 0, 1, 0};    // di
static const int NIL = -1;
*/

typedef unsigned long long ull;
typedef long long ll;
typedef vector<ll> Vector;
typedef vector<Vector> DVector;
typedef vector< pair<ll, ll> > Vec_Pair;
// 関数prime_factorizationで使う。
// 因数分解で使う。firstは数。secondは指数。
vector< pair<ll, ll> > prime_factor;
// 関数get_factor_listで使う。因数の一覧を取得で使う。
Vector factor_list;
// ２つともエラトステネスの篩で使う。
vector<bool> prime; // 素数かどうか判定。
Vector prime_num;   // 素数を記録。

ll n, N, k, K;

template <class X> void printArray(X *array, ll);
template <class X> void printVector(vector<X> &v);
template <class X> void printDimention(vector< vector<X> > &dv);
template <class X> void printMap(X);
template <class X> void printVecPair(vector<X> &v);
// 何個2がかかっているか
ll factor2(ll);
//nCr方式で組み合わせの数を求める
ll combination(ll, ll);
//nPrで階乗を求める
int factorial(int, int);
//桁数を返す
ll find_digits(ll);
// 各桁の和を計算する関数
int findSumOfDigits(int);
//次数を得る
int degree(int);
//四捨五入
int shishagonyu(double);
//切り上げ
int roundUp(double);
//切り捨て
int roundDown(double);
//四捨五入
int roundOff(double);
//最大公約数(Greatest Common Divisor)
ll gcd (ll, ll);
//最小公倍数(Least Common Multiple)
ll lcm(ll, ll);
//素因数分解
void prime_factorization(ll);
//エラトステネスの篩
void Eratosthenes(int);
//偶奇判定。奇数ならtrue。
bool odd_even(int);
//aのmod mにおける逆元を計算する
long long modinv(long long, long long);
// a^n mod を計算する（二分累乗）
long long modpow(long long, long long, long long);
//テーブルを作る前処理
void COMinit();
//二項係数計算 nCk, 1 <= k <= n <= 10^7
long long COM(ll, ll);
// longlong型で絶対値を帰す。
long long abs_ll(ll);
// 割り算した時に余りが有る時だけ、+1の商を返す。
long long div_one(ll, ll);
// Stringの各桁をvectorの配列に入れる。でかい桁が添字0。
template <class X> void StringtoVec(string, vector<X> &v);
// 因数の一覧を取得する
void get_factor_list(ll);

int main(int argc, char const *argv[])
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    ll D, A;
    ll X, H;
    Vec_Pair XH;
    Vec_Pair Bomb;

    cin >> N >> D >> A;

    rep(i, N){
        cin >> X >> H;
        XH.push_back(make_pair(X, H));
    }
    sort(XH.begin(), XH.end());
    //printVecPair(XH);

    ll res = 0;
    rep(i, N){
        X = XH[i].first;   H = XH[i].second;
        //DEBUG_VARIABLE(i);
        // 既に起こった爆発があるか
        while(Bomb.size() != 0 && X > Bomb[0].first){  // その爆風は届いてない
            //cout << "not blast" << endl;
            Bomb.erase(Bomb.begin());
        }
        if(Bomb.size() != 0){    // 爆発のダメージを加算しているので、一番上だけ見れば良い
            // 爆風でダメージを受ける
            H -= Bomb[0].second;
            //cout << "blast "  << H << endl;
        }
        //printVecPair(Bomb);
        if(H <= 0)  continue;   // モンスターが死んだ
        // モンスターが死んでないので爆発を起こす
        ll times = (H + A - 1) / A;
        ll damage = times * A;
        // 爆風がギリギリかかるところに、爆発を起こす
        ll right_edge = X + 2 * D;
        //cout << "new bomb: times " << times << " :right_edge " << right_edge << endl;
        rep(j, Bomb.size()){   // 既に起こった爆発に加算する
            if(X <= Bomb[j].first)    Bomb[j].second += damage;
            else    break;
            //cout << "add bomb: right_edge " << Bomb[j].first << " :damage " << Bomb[j].second << endl;
        }
        // 爆風がどこまで届くかを記録しておく
        Bomb.push_back(make_pair(right_edge, damage));
        res += times;
        //DEBUG_VARIABLE(times);
    }
    cout << res << endl;

    return 0;
}

template<class X> void printArray(X array[], ll n){
    rep(i, n){
        if(i)   cout << " ";
        cout << array[i];
    }
    cout << endl;
}

template<class X> void printVector(vector<X> &v){
    rep(i, (int)v.size()){
        if(i)   cout << " ";
        cout << v[i];
    }
    cout << endl;
}

//二次元配列の表示
template<class X> void printDimention(vector< vector<X> > &dv){
    rep(i, (ll)dv.size()){
        rep(j, (ll)dv[i].size()){
            if(j)   cout << " ";
            cout << dv[i][j];
        }
        cout << endl;
    }
}

//mapの表示
template <class X> void printMap(X mp) {
    for (auto it : mp) {
        cout << it.first << " " << it.second << endl;
    }
}

// 内部にpairを内包したvectorの表示
template <class X> void printVecPair(vector<X> &v){
    rep(i, (int)v.size()){
        cout << v[i].first << " " << v[i].second << endl;
    }
    cout << endl;
}

//numの中に何個2がかかってるか
ll factor2(ll num){
    int cnt = 0;
    while(num % 2 == 0){
        num /= 2;
        cnt++;
    }
    return cnt;
}

//nCr方式で組み合わせの数を求める
ll combination(ll n, ll r){
    if(n == 0 || r == 0 || n < r)    return 0;
    ll up = 1, down = 1;
    // 以下2行はお試し
    ll half = n / 2;
    if(r >= half)   r = n - r;
    ll up_tmp = n, down_tmp = r;

    if(r == 0)  return 1;
    rep(i, r){
        up *= up_tmp;
        up_tmp--;
        down *= down_tmp;
        down_tmp--;
    }

    return up/down;
}



//nPr方式で階乗を求める
int factorial(int n, int r){
    if(n < r){
        cout << "error" << endl;
        return 0;
    }else{
        int res = 1;
        while(r){
            r--;
            res *= n;
            n--;
        }
        return res;
    }
}

//桁数を返す
ll find_digits(ll n){
    int digit = 0;

    while(n){
        n /= 10;
        digit++;
    }
    return digit;
}
// 各桁の和を計算する関数
int findSumOfDigits(int n){
    int sum = 0;
    while (n > 0) { // n が 0 になるまで
        sum += n % 10;
        n /= 10;
    }
    return sum;
}
//次数を得る
int degree(int n){
    int count = 0;
    while(1){
        if(count <= 0)  break;
        count /= 2;
        count++;
    }
    return count;
}

//四捨五入
int shishagonyu( double x )
{
    return (int)( x < 0.0 ? x-0.5 : x+0.5 );
}

//切り上げ
int roundUp(double n){
    if(n >= 0){
        return (int)n + 1;
    }else{
        return (int)n - 1;
    }
}

//切り捨て
int roundDown(double n){
    return (int)n;
}

//四捨五入
int roundOff(double n){
    double decimal = 0;

    decimal = n - (int)n;

    if(decimal >= 0.5 || decimal <= -0.5){
        return roundUp(n);
    }else{
        return roundDown(n);
    }
}

//最大公約数(Greatest Common Divisor)
ll gcd (ll a, ll b){
    return b ?  gcd(b, a % b) : a;
}
/*
ll gcd (ll m, ll n){
    //引数に0がある場合は0を返す
    if(m == 0 || n == 0)    return 0;
    if(m == 1 || n == 1)    return 1;
    
    //ユークリッドの互除法
    while(m != n){
        if(m == 1 || n == 1)    return 1;

        if(m > n)   m = m - n;
        else    n = n - m;
    }
    return m;
}
*/

//最小公倍数(Least Common Multiple)
ll lcm(ll m, ll n){
    //引数に0がある場合は0を返す
    if(m == 0 || n == 0)    return 0;
    
    //lcm = m * n / gcd(m, n)
    return ((m / gcd(m, n)) * n);
}

//素因数分解 firstは数。secondは指数。
void prime_factorization(ll n){
    int div = 2, res;
    
    bool flg = false;
    if(n < 2){
        cout << "Error" << endl;
        return;
    }
    while(n >= div * div){
        if(n % div == 0){
            res = div;
            //resをグローバルな配列に代入すれば記録できる。
            if(flg){
                prime_factor[prime_factor.size() - 1].second++;
            }else{
                prime_factor.push_back(make_pair(0, 1));
                prime_factor[prime_factor.size() - 1].first = res;
            }
            n /= div;
            flg = true;
        }else{
            div++;
            flg = false;
        }
    }
    //ラス1の素因数
    res = n;
    if(prime_factor[prime_factor.size() - 1].first == res){
        prime_factor[prime_factor.size() - 1].second++;
    }else{
        prime_factor.push_back(make_pair(res, 1));
    }
}

//エラトステネスの篩
void Eratosthenes(int n){
    // prime_bool の添え字と見たい数は一致させたいので、
    // prime_boolやprime_numは１つ多く宣言すること。
    prime[0] = false;
    prime[1] = false;
    
    for(int i = 2; i < sqrt(n); i++){
        if(prime[i]){
            for(int j = 0; i * (j + 2) < n; j++){
                prime[i *(j + 2)] = false;
            }
        }
    }
    // 素数をprime_numに記録
    rep(i, n){
        if(prime[i])    prime_num.push_back(i);
    }
    /*
    int cnt = 0;
    for(int i = 2; i < n; i++){
        if(prime[i]){
            cnt++;
        }
    }
    return cnt;
    */
}
//偶奇判定。奇数ならtrue。
bool odd_even(int num){
    bool judge;
    if(num % 2){
        judge = true;
    }else{
        judge = false;
    }
    return judge;
}
//aのmod mにおける逆元を計算する
long long modinv(long long a, long long m) {
    long long b = m, u = 1, v = 0;
    while (b) {
        long long t = a / b;
        a -= t * b; swap(a, b);
        u -= t * v; swap(u, v);
    }
    u %= m;
    if (u < 0) u += m;
    return u;
}
// a^n mod を計算する
long long modpow(long long a, long long n, long long mod) {
    long long res = 1;
    while (n > 0) {
        if (n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}
//main関数内でCOMinitを呼んだ後，COMを呼ぶ．
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < TABLEMAX; i++){
        fac[i] = fac[i - 1] * i % MOD;
    }
    for (int i = 2; i < TABLEMAX / 2; i++){
        inv[i] = MOD - inv[MOD % i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}
// 二項係数計算 nCk, nCrのcombinationでも使える
long long COM(ll n, ll k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

long long abs_ll(ll a){
    if(a >= 0){
        return a;
    }else{
        return -a;
    }
}

// 割り算した時に余りが有る時だけ、+1の商を返す。
long long div_one(ll res, ll div){
    // res 割られる数、div 割る数
    return (res + div - 1)/div;
}

// Stringの各桁をvectorの配列に入れる。でかい桁が添字0。
template <class X> void StringtoVec(string str, vector<X> &v){
    ll num = stoll(str);
    ll it = str.size() - 1;
    // 桁を逆にしたい時、下をon
    //ll it = 0;
    v.resize(str.size());
    while(num){
        v[it] = num % 10;
        num /= 10;
        it--;
        //it++;
        if(it < 0){
            cout << "reference error" << endl;
            break;
        }
    }
}

// nに数を入れるとその約数の一覧をfactor_listに格納する
void get_factor_list(ll n){
    int div = 1, res;

    while(n >= div * div){
        if(n % div == 0){
            res = div;
            ll tmp = n / res;
            factor_list.push_back(res);
            if(tmp != 1)    factor_list.push_back(tmp);
            div++;
        }else{
            div++;
        }
    }
    sort(factor_list.begin(), factor_list.end());
}

// 簡単な繰返し自乗法
// 再帰を使いながら高速で
ll RepeatSquaring(ll N, ll P, ll M){
    // Nは基数、Pは指数、MはMOD
    if(P == 0)  return 1;
    if(P % 2 == 0){
        ll tmp = RepeatSquaring(N, P/2, M);
        return tmp * tmp % M;
    }else{
        return N * RepeatSquaring(N, P - 1, M) % M;
    }
}