import std.stdio, std.conv, std.string, std.bigint;
import std.math, std.random, std.datetime;
import std.array, std.range, std.algorithm, std.container, std.format;
string read(){ static string[] ss; while(!ss.length) ss = readln.chomp.split; string res = ss[0]; ss.popFront; return res; }

/*
数直線上で、sからs + wまでの位置を占めるブロックであると考える
所定の位置よりも左に配置することは可能
他のブロックと重ならないように並べる

s + w が小さいものから順に使うとしてよい
そのようにソートしておく

右端がk以内で、i番目のブロックまで使っているときの価値の最大を
x[i][k]

k - B[i].w > B[i].s のとき
x[0][k] = B[0].v
x[i][k] = max(x[i - 1][k], x[i][k - 1])

k - B[i].w >= 0 かつ k - B[i].w <= B[i].s のとき
x[0][k] = B[0].v
x[i][k] = max(x[i - 1][k - B[i].w] + B[i].v, x[i - 1][k], x[i][k - 1])

k - B[i].w < 0 のとき
x[0][k] = 0
x[i][k] = x[i - 1][k]

*/

void main(){
	long n = read.to!long;
	
	Block[] blocks;
	foreach(i; 0 .. n){
		blocks ~= new Block(read.to!long, read.to!long, read.to!long);
	}
	debug writeln("blocks:", blocks);
	
	blocks.sort!"a.s+a.w<b.s+b.w"();
	debug writeln("blocks:", blocks);
	
	long kmax;
	foreach(b; blocks) kmax += b.s + b.w;
	debug writeln("kmax:", kmax);
	
	long[][] xs = new long[][](n, kmax);
	foreach(i; 0 .. n){
		foreach(k; 0 .. kmax){
			long l = k - blocks[i].w;
			if(l >= 0 && l <= blocks[i].s){
				if(i == 0) xs[i][k] = blocks[i].v;
				else xs[i][k] = max(xs[i - 1][k - blocks[i].w] + blocks[i].v, xs[i - 1][k], xs[i][k - 1]);
			}
			else if(l >= 0){
				if(i == 0) xs[i][k] = blocks[i].v;
				else if(k > 0) xs[i][k] = max(xs[i - 1][k], xs[i][k - 1]);
				else xs[i][k] = xs[i - 1][k];
			}
			else{
				if(i == 0) xs[i][k] = 0;
				else xs[i][k] = xs[i - 1][k];
			}
		}
	}
	debug writeln("xs:", xs);
	
	xs[n - 1][kmax - 1].writeln;
}


class Block{
	long w, s, v;
	this(long w, long s, long v){
		this.w = w;
		this.s = s;
		this.v = v;
	}
	override string toString(){
		return "(" ~ s.to!string ~ ", " ~ w.to!string ~ ", " ~ v.to!string ~ ")";
	}
}

