#include <iostream>
#include <cstdlib>
#include <map>
#include <tuple>
#include <iomanip>
#include <cmath>
#include <algorithm>
#include <cassert>


using namespace std;

class Hypothesis {
	double weight;
	map<tuple<int, int>, double> memo;

public:
	Hypothesis(double weight) :
		weight(weight)
	{

	}

	double open_chance(int opened) {
		int closed = 36 - opened;
		double result = (double)closed / (weight * opened + closed);
		assert(0 <= result && result <= 1);
		return result;
	}

	double likelihood(int total, int opened) {
		if (total == 0 && opened == 0) return 1;
		if (total == 0 || opened == 0) return 0;

		auto hit = memo.find(make_tuple(total, opened));
		if (hit != memo.end()) return hit->second;

		auto result =
			likelihood(total - 1, opened) * (1 - open_chance(opened)) +
			likelihood(total - 1, opened - 1) * open_chance(opened - 1);

		memo[make_tuple(total, opened)] = result;
		assert(0 <= result && result <= 1);
		return result;
	}

	double log_likelihood(int total, int opened) {
		return log(likelihood(total, opened));
	}
};

int main()
{
	struct input_type {
		int opened;
		int total;
	};
	input_type inputs[] = {
		input_type{ 25, 53 },
		input_type{ 28, 72 },
		input_type{ 25, 72 },
		input_type{ 29, 72 },
		input_type{ 27, 69 }
	};


	int N = 50;

	for (int i = -N; i <= N; ++i) {
		double wight = pow(10, (double)i / N);
		Hypothesis hypothesis(wight);
		double sum = 0;
		for (auto input : inputs) {
			sum += hypothesis.log_likelihood(input.total, input.opened);
		}

		int barlength = (int)round(20 + sum);
		if (barlength < 0) barlength = 0;
		if (barlength > 20) barlength = 20;

		string bar = string(barlength, ' ') + string(20 - barlength, '*') + "|";

		cout << setw(12) << wight << "\t" << setw(12) << sum << "\t# " << bar << endl;
	}

}

