Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], skipTags: ["script","noscript","style","textarea","code"], processEscapes: true }});

問題文

実数変数 $x_1, x_2, ..., x_N$ は以下の条件を満たす。

$0 \leq x_i \leq 1$ ($1 \leq i \leq N$)

$w_1x_1+w_2x_2+...+w_Nx_N \leq W$

このとき $v_1x_1+v_2x_2+...+v_Nx_N$ のとりうる最大値を求めよ。そのような最大値は実際に存在することが知られている。

入力

入力は以下の形式に従う。与えられる数は全て整数である。

$N$ $W$
$w_1$ $v_1$
$w_2$ $v_2$
$...$
$w_N$ $v_N$

制約

$1 \leq N \leq 10^5$

$1 \leq W \leq 10^5$

$-10^4 \leq w_i \leq 10^4$

$-10^4 \leq v_i \leq 10^4$

出力

$v_1x_1+v_2x_2+...+v_Nx_N$ のとりうる最大値を1行に出力せよ。
出力には $10^{-3}$ を超える誤差があってはならない。

Sample Input 1

1 1
3 1

Output for the Sample Input 1

0.333333

$x_1=1/3$ のとき最大となる。

Sample Input 2

2 3
3 3
1 2

Output for the Sample Input 2

4.000000

Sample Input 3

2 1
-1 -3
3 10

Output for the Sample Input 3

3.666667

Solution in JAVA (judge verdict: Accepted)

import java.util.Arrays;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Scanner;
 
 
public class Main{
	
	public static class Pair implements Comparable<Pair>{
		int w, v;
		
		public Pair(int w, int v) {
			super();
			this.w = w;
			this.v = v;
		}

		@Override
		public int compareTo(Pair o) {
			return this.w * o.v - this.v * o.w;
		}
	}
	
    public static void main(String[] args){
    	final Scanner sc = new Scanner(System.in);
    	
    	final int N = sc.nextInt();
    	final int W = sc.nextInt();
    	
    	PriorityQueue<Pair> queue = new PriorityQueue<Main.Pair>(); 
    	
    	double cur_w = 0, cur_v = 0;
    	
    	for(int i = 0; i < N; i++){
    		int w = sc.nextInt();
    		int v = sc.nextInt();
    		
    		if(w >= 0 && v <= 0){
    			continue;
    		}else if(w <= 0 && v >= 0){
    			cur_w += w;
    			cur_v += v;
    			continue;
    		}else if(w <= 0 && v <= 0){
    			cur_w += w;
    			cur_v += v;
    			
    			w = -w;
    			v = -v;
    		}
    		
    		queue.add(new Pair(w, v));
    	}
    	
    	
    	while(!queue.isEmpty()){
    		Pair p = queue.poll();
    		
    		final double rest = W - cur_w;
    		final double x = Math.max(0, Math.min(1, rest / p.w));
    		
    		//System.out.println(cur_w + " "+ rest + " "+ p.v + " " + p.w + " " + x);
    		
    		cur_w += x * p.w;
    		cur_v += x * p.v;
    	}
    	
    	System.out.printf("%f\n", cur_v);
    }
     
}