Problem:
A: Attack the Moles

ICPC で良い成績を収めるには修行が欠かせない．うさぎは ICPC で勝ちたいので，今日も修行をすることにした．

今日の修行は，もぐらたたきを何回も行って，反射神経と記憶力を高めようというものである．出てくるもぐらを次々に叩き，出来るだけ多くのポイントを獲得したい．

もぐらが出てくる可能性のある場所は直線状に並んでいて，基準点からの距離によって座標が定まっている．うさぎはしばらく修行を続けるうちに，もぐらの出現する場所と時間が常に一緒であることに気が付いた．うさぎは，その情報をすべて記録し，コンピュータで解析を行うことにした．

もぐらを叩くには，もぐらの出現位置に手を動かした後，もぐらの出てくるタイミングにぴったり合わせてもぐらを叩かなければならない．もぐらをうまく叩けると，そのもぐらに応じてポイントを得ることが出来る．もぐらを叩く動作は一瞬で行うことが出来るが，手を移動させる速さには限界がある．うさぎはもぐらを叩くにあたって左右両方の手を用いることができる．左手と右手は独立に動かすことが可能であるが，左手は常に右手より座標が小さい位置に存在しなければならない．このような条件下で，最大でどれだけのポイントが得られるかを調べたい．

Input

N V XLeft XRight
X1 T1 P1
...
XN TN PN

N は出てくるもぐらの数，V は手を移動させられる最大の速さ，XLeft, XRight はそれぞれ，左手，右手の初期位置の座標である．Xi, Ti, Pi はそれぞれ，i 番目のもぐらの，出現する位置の座標，ゲーム開始から出現までの時間，叩けた際に得られるポイントである．

1 ≤ N ≤ 3,000，1 ≤ V ≤ 10,000，1 ≤ XLeft < XRight ≤ 100,000，1 ≤ X1 ≤ X2 ≤ ... ≤ XN ≤ 100,000，1 ≤ Ti ≤ 100,000，1 ≤ Pi ≤ 100,000 を満たす．(Xi, Ti) として同一の組は複数回現れない．

Output

うさぎが得られる最大のポイントを 1 行に出力せよ．

Sample Input 1

3 10 150 250
100 20 123
201 10 67
202 10 45

Sample Output 1

190

Sample Input 2

1 7 20 90
55 5 73

Sample Output 2

73

Sample Input 3

10 2 1000 2000
400 300 1
600 200 1
700 800 1
700 500 1
900 600 1
1000 700 1
1300 900 1
1400 400 1
1500 1000 1
2000 100 1

Sample Output 3

10

Solution in JAVA (judge verdict: Memory Limit Exceeded)

import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;
import java.util.Scanner;


public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int v = sc.nextInt();
        int xl = sc.nextInt();
        int xr = sc.nextInt();
        int pointSum = 0;
        Mogura[] moguras = new Mogura[n];
        for (int i = 0; i < n; i++) {
            moguras[i] = new Mogura(sc.nextInt(), sc.nextInt(), sc.nextInt());
            pointSum += moguras[i].p;
        }
        Arrays.sort(moguras);
        int[] remPoints = new int[n];
        remPoints[0] = pointSum;
        for (int i = 1; i < moguras.length; i++) {
            remPoints[i] = remPoints[i-1] - moguras[i-1].p;
        }
        //System.out.println(Arrays.toString(moguras));
        
        Queue<State> states = new ArrayDeque<State>(n*n);
        states.add(new State(xl, xr, 0, 0, 0));
        int curMax = 0;
        for (int i = 0; i < n; i++) {
            int nextCurMax = curMax;
            Mogura mogura = moguras[i];
            int size = states.size();
            for (int j = 0; j < size; j++) {
                State state = states.poll();
                if(state.p + remPoints[i] <= curMax) {
                    continue;
                }
                states.add(state);
                //System.out.println(state);
                int dtLeft = mogura.t - state.leftT;
                int dxLeftRange = dtLeft * v;
                int dtRight = mogura.t - state.rightT;
                int dxRightRange = dtRight * v;
                int nextPoint = state.p + mogura.p;
                boolean tapped = false;
                if(state.leftX - dxLeftRange <= mogura.x && mogura.x <= state.leftX + dxLeftRange
                        && mogura.x < state.rightX + dxRightRange) {
                    //ツ債カツ偲ィツづつスツつスツつッツづゥ
                    int rightTime = mogura.x < state.rightX ? 0 : (mogura.x - state.rightX + v) / v;
                    int rightX = mogura.x < state.rightX ? state.rightX : mogura.x + 1; 
                    states.add(new State(mogura.x, rightX, mogura.t, state.rightT + rightTime, nextPoint));
                    //System.out.println("addl");
                    tapped = true;
                    
                }
                if(state.rightX - dxRightRange <= mogura.x && mogura.x <= state.rightX + dxRightRange
                        && state.leftX - dxLeftRange < mogura.x) {
                    //ツ右ツ偲ィツづつスツつスツつッツづゥ
                    int leftTime = state.leftX < mogura.x ? 0 : (state.leftX - mogura.x + v) / v;
                    int leftX = state.leftX < mogura.x ? state.leftX : mogura.x - 1; 
                    states.add(new State(leftX, mogura.x, state.leftT + leftTime, mogura.t, nextPoint));
                    tapped = true;
                    //System.out.println("addr");
                }
                if (tapped) {
                    if(nextCurMax < nextPoint) nextCurMax = nextPoint;
                }
            }
            curMax = nextCurMax;
        }
        System.out.println(curMax);
    }
    
    static class State {
        final int leftX;
        final int rightX;
        final int leftT;
        final int rightT;
        final int p;
        
        public State(int leftX, int rightX, int leftT, int rightT, int p) {
            this.leftX = leftX;
            this.rightX = rightX;
            this.leftT = leftT;
            this.rightT = rightT;
            this.p = p;
        }

        @Override
        public String toString() {
            return "State [leftX=" + leftX + ", rightX=" + rightX + ", leftT=" + leftT
                    + ", rightT=" + rightT + ", p=" + p + "]";
        }
    }
    
    static class Mogura implements Comparable<Mogura> {
        final int x;
        final int t;
        final int p;
        public Mogura(int x, int t, int p) {
            this.x = x;
            this.t = t;
            this.p = p;
        }
        @Override
        public int compareTo(Mogura o) {
            return t - o.t;
        }
        @Override
        public String toString() {
            return "Mogura [x=" + x + ", t=" + t + ", p=" + p + "]";
        }
        
        
    }

}