/*
目标点i在目标点x(i),该点得分为p(i) 开始时可以选择站在一个目标点上,只允许朝一个方向跳跃,从一目标点跳到另外一个目标点,每次跳跃的距离至少和上一次跳跃的距离相等,并且必须跳到一个目标点。
每跳到一个目标点,贝西可以拿到该点的得分,请计算他的最大可能得分
f[i][dis]:当前点是i 上一次跳了dis
f[i][dis]=max(f[j][k]+p[i]) p[i]-p[j]==dis>k
->O[nk] TLE
f[i][j]:point i->point j max score
f[i][j]=max[f[k][j]+p[i]] x[j]-x[k]<=x[i]-x[j] f[i][i]=p[i]
->O[n^3] TLE
但是f[i][j] i->j存储的 先循环j i 在读取fij缓存 时数据连续 n^3/10
f[i][j]=max[f[k][j]]+p[i] k j i x(j)−x(k)≤x(i)−x(j) (k<=j,j<=i)
f[i-1][j]=max[f[k][j]]+p[i-1] (k<=j,j<=i-1)
f[i][j]=f[i-1][j]-p[i-1]+p[i] x(j)−x(k)≤x(i−1)−x(j)
所以k的范围变大 最大值更大了
*/
/*
6
5 6
1 1
10 5
7 6
4 8
8 10
25
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
#include<bits/stdc++.h>
typedef long long ll;
#define ddd printf("-----------------------\n");
using namespace std;
const int maxn=1e1 +10;
const int mod=998244353;
const int inf=0x3f3f3f3f;
int read()
{
int res=0,f=1;char ch=getchar();
while(isdigit(ch)==0){ if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)){ res=res*10+ch-'0'; ch=getchar();}
return f*res;
}
int n,f[2010][2010],ans;
struct node{
int x,p;
bool operator<(const node &b)const{
return x<b.x;
}
}a[2010];
int main()
{
ios::sync_with_stdio(false);
// cin>>n;
n=read();//cout<<n<<endl;
for(int i=1;i<=n;i++) a[i].x=read(),a[i].p=read();
sort(a+1,a+1+n);
for(int j=1;j<=n;j++)//k j i
{
for(int i=j+1;i<=n;i++)
{
f[j][j]=a[j].p;
int tmp=a[j].p;//可能不存在
for(int k=j-1;k>=1;k--)
{
if(a[i].x-a[j].x>=a[j].x-a[k].x)
tmp=max(tmp,f[j][k]);
}
f[i][j]=tmp+a[i].p;
ans=max(ans,f[i][j]);
}
}
memset(f,0,sizeof(f));
for(int j=n;j>=1;j--)//i j k
{
for(int i=j-1;i>=1;i--)
{
f[j][j]=a[j].p;
int tmp=a[j].p;
for(int k=j+1;k<=n;k++)
{
if(-a[i].x+a[j].x>=-a[j].x+a[k].x)
tmp=max(tmp,f[j][k]);
}
f[i][j]=tmp+a[i].p;
ans=max(ans,f[i][j]);
}
}
cout<<ans<<'\n';
return 0;
}