#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
#include <cmath>
#include <queue>
#include <string>
using namespace std;

using ld = float;
using vld = vector<ld>;

vld generate(int n)
{
	vld result;
	for (; n > 0; n--)
		result.push_back(ld(1) / n / n);
	reverse(result.begin(), result.end());
	return result;
}

ld sum_series()
{
	ld pi = acos(ld(0)) * 2;
	return pi * pi / 6;
}

ld sum_naive(vld v)
{
	ld result = 0;
	for (auto d : v)
		result += d;
	return result;
}

ld sum_recursive_range(const vld &v, int l, int r)
{
	if (l == r)
		return v[r];

	int mid = (l + r) / 2;
	return sum_recursive_range(v, l, mid) + sum_recursive_range(v, mid + 1, r);
}

ld sum_recursive(vld v)
{
	random_shuffle(v.begin(), v.end());
	return sum_recursive_range(v, 0, (int)v.size() - 1);
}

ld sum_huffman(vld v)
{
	priority_queue<ld, vector<ld>, greater<ld>> q(v.begin(), v.end());
	while (q.size() != 1)
	{
		auto d1 = q.top();
		q.pop();
		auto d2 = q.top();
		q.pop();
		q.push(d1 + d2);
	}
	return q.top();
}

void dump(string prefix, ld x)
{
	cout << prefix << ": " << x << " (error " << fabs(x - sum_series()) << ")" << endl;
}

void dump(int n)
{
	auto v = generate(n);

	cout << "Case #" << n << endl;
	dump("Naive direct", sum_naive(v));
	reverse(v.begin(), v.end());
	dump("Naive reversed", sum_naive(v));

	dump("Recursive 1", sum_recursive(v));
	dump("Recursive 2", sum_recursive(v));
	dump("Recursive 3", sum_recursive(v));
	dump("Recursive 4", sum_recursive(v));

	dump("Huffman", sum_huffman(v));
}

int main()
{
	srand(322);

	cout.setf(ios::fixed);
	cout.precision(20);

	cout << "Series sum: " << sum_series() << endl;
	dump(10000000);

	return 0;
}

