Mixing Water

Problem Info

Mixing Water- Codeforces

My Work

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/**
 * https://codeforces.com/problemset/problem/1359/C
 * 3
 * 30 10 20
 * 41 15 30
 * 18 13 18 should output 2, 7, and 1, each on a newline
 */
public final class WaterMix {
    public static void main(String[] args) throws IOException {
        BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
        int testNum = Integer.parseInt(read.readLine());
        for (int t = 0; t < testNum; t++) {
            StringTokenizer info = new StringTokenizer(read.readLine());
            int hot = Integer.parseInt(info.nextToken());
            int cold = Integer.parseInt(info.nextToken());
            int target = Integer.parseInt(info.nextToken());
            if (cold > hot) {
                throw new IllegalArgumentException("invalid water temperatures lol");
            }
            double closest = Math.abs(hot - target);
            int cupNum = 1;

            double avg = (double) (hot + cold) / 2;
            if (Math.abs(avg - target) < closest) {
                cupNum = 2;
                closest = Math.abs(avg - target);
            }
            if (avg < target) {
                int theoretical = (cold - hot) / (hot + cold - 2 * target);
                int loOdd = (theoretical - 1) / 2 * 2 + 1;
                double loOddTemp = ((double) (loOdd - 1) * (hot + cold) / 2 + hot) / loOdd;
                if (Math.abs(loOddTemp - target) < closest) {
                    closest = Math.abs(loOddTemp - target);
                    cupNum = loOdd;
                }

                int hiOdd = loOdd + 2;
                double hiOddTemp =  ((double) (hiOdd - 1) * (hot + cold) / 2 + hot) / hiOdd;
                if (Math.abs(hiOddTemp - target) < closest) {
                    cupNum = hiOdd;
                }
                System.out.println(loOddTemp + " " + hiOddTemp);
            }
            System.out.println(cupNum);
        }
    }
}

It’s an O(T) solution using some math voodoo. The thing is, it fails for this test case, where for

1
999977 17 499998

should output 499981, but my program outputs 499979.
However, I checked the average temperature for both, and they’re the same up to maximum precision.

How could I achieve greater precision?

Consider using my code for reference:

#include <bits/stdc++.h>
using namespace std;
double hot_water, cold_water, desired_temp;
/*
	* This function checks whether pouring cupsPoured amount of cups achieves an average
	* barrel temperature greater than or equal to desired_temp. Technically, this represents
	* 2 * cupsPoured + 1 cups
*/
bool works (int cupsPoured) {
	double totalBarrelTemperature = (hot_water * (cupsPoured + 1) + cold_water * (cupsPoured));
	double totalCupsPoured = (double) (2 * cupsPoured + 1.0);
	double avgBarrelTemperature = totalBarrelTemperature / totalCupsPoured;
	return avgBarrelTemperature >= desired_temp;
}
void solve () {
	/* 
	   * maximumCups represents the the maximum number of cups such
	   * that the barrel temperature is greater than desired_temp.
	*/
	cin >> hot_water >> cold_water >> desired_temp;
	// Binary search on the answer for maximumCups.
	int left = 0, right = 1e6 + 1, maximumCups = 0;
	while (left <= right) {
		int mid = left + (right - left) / 2;
		if (works(mid)) {
			maximumCups = mid;
			left = mid + 1;
		} else {
			right = mid - 1;
		}
	}
	// If it is impossible to find a temperature close to desired_temp, then print 2
	if (maximumCups == 1e6 + 1) {
		cout << 2 << endl;
	} else {
		/*
		   * The solution must lie between barrel1 and barrel2 if the total number of cups
		   * is odd. barrel1 represents the barrel with an average temperature slightly
		   * greater than desired_temp. barrel2 represent the barrel with an average
		   * temperature slightly less than desired_temp. These two barrels will be the
		   * closest to desired_temp.
		*/
		double totalBarrel1 = (hot_water * (maximumCups + 1) + cold_water * (maximumCups));
		double totalBarrel2 = (hot_water * (maximumCups + 2) + cold_water * (maximumCups + 1));
		double barrel1Cups = (double)(2 * maximumCups + 1.0);
		double barrel2Cups = (double)(2 * maximumCups + 3.0);
		double avgBarrel1 = (totalBarrel1) / barrel1Cups;
		double avgBarrel2 = (totalBarrel2) / barrel2Cups;
		double hot_cold_avg = (hot_water + cold_water) / 2.0;
		double minAbsDifference = min(abs(desired_temp - avgBarrel1),
		min(abs(desired_temp - avgBarrel2),
		abs(desired_temp - hot_cold_avg)));
		
		/*
		   * If the minimum absolute difference from desired_temp is
		   * hot_cold_avg, then it suffices to print 2. Otherwise, print
		   * the barrel with the minimum absolute difference from desired_temp.
		*/
		if (minAbsDifference == abs(desired_temp - hot_cold_avg)) {
			cout << 2 << endl;
		} else if (minAbsDifference == abs(desired_temp - avgBarrel1)) {
			cout << 2 * maximumCups + 1 << endl;
		} else {
			cout << 2 * maximumCups + 3 << endl;
		}
	}
}
int main() {
	int t; cin >> t;
	for (int i = 1; i <= t; i++) {
		solve();
	}
}