// 想定解法: DP #include #include #include #include using namespace std; #define REP(i, n) for(int(i)=0;(i)<(n);++(i)) #define RREP(i, n) for(int(i)=(n)-1;(i)>=0;--(i)) void rc(int v,int mn,int mx){if(v s[MAXT*2+1]; bool dp[MAXT*2+1]; pair p; int main(){ cin >> N; rc(N,1,MAXN); int maxt = 0; REP(i,N){ cin >> V >> T; rc(V,1,MAXV); rc(T,1,MAXT); s[T+V].insert(T); maxt = max(maxt, T+V); } dp[0] = true; int res = 0; REP(i,maxt+1){ for(auto it = s[i].begin(); it != s[i].end(); ++it){ int v = i - *it; RREP(j,*it){ int k = j+v; if(dp[j]){ if(k < MAXT*2) dp[k] = true; res = max(res, k); } } } } cout << res << endl; return 0; } /* 解説 T+Vが小さい順にソートしてDP 家1がV1 T1、家2がV2 T2だとすると 家1に行った場合の所持数の可能性が[V1,V1+T1-1]の範囲、 家1に行った場合の所持数の可能性が[V2,V2+T2-1]の範囲となる。 なので、行った結果の所持数の最大が小さい順にDP 自信がないけどたぶん(´・_・`) */