#include <map>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <functional>
#include <fstream>
#include <stdexcept>
#include <numeric>
#include <cctype>
#include <iterator>
#include <utility>

typedef std::map<char, int> freq_t;
typedef std::vector< std::pair<char, int> > freqv_t;

struct calc_freq
: std::unary_function< freq_t, char* >
{
  freq_t operator()(char* filename) const
  {
    std::ifstream ifs(filename);
    if ( !ifs )
      throw std::runtime_error(std::string("failed to open : ")+filename);

    freq_t f;
    while ( ifs )
    {
      int c = ifs.get();
      if (c >= 0) ++f[c];
    }

    return f;
  }
};

struct merge_freq
: std::binary_function<freq_t, freq_t, freq_t>
{
  freq_t& operator()(freq_t& lhs, const freq_t& rhs) const
  {
    for ( freq_t::const_iterator it = rhs.begin();
        it != rhs.end(); ++it )
      lhs[it->first] += it->second;

    return lhs;
  }
};

struct count_total
: public std::binary_function< int, int, freq_t::value_type >
{
  int& operator()(int& total, const freq_t::value_type& v) const
  {
    return total += v.second;
  }
};

template<class C>
struct freq_print_each
: std::unary_function< void, typename C::value_type >
{
  std::size_t total_;
  mutable std::size_t i_;
  freq_print_each<C>(std::size_t total) : total_(total), i_(0) {}

  void operator()(const typename C::value_type& v) const
  {
    std::cout << std::setw(3) << ++i_ << ":" << std::setw(4);
    if ( !isprint(v.first) || isspace(v.first) )
      std::cout << std::showbase << std::hex
                 << static_cast<int>(v.first) << std::dec;
    else
      std::cout << v.first;

    std::cout << std::setw(8)
      << v.second << " ("
      << std::setprecision(5) << std::fixed
      << static_cast<double>(v.second)/total_
      << ")\n";
  }
};

template <class C>
struct sorter
: std::binary_function<bool, typename C::value_type, typename C::value_type>
{
  typedef typename C::value_type value_type;
  bool operator()(const value_type& lhs, const value_type& rhs) const
  {
    return lhs.second > rhs.second;
  }
};

int main(int c, char** v)
{
  try {
    std::vector< freq_t > freqs;
    std::transform(v+1, v+c, std::back_inserter(freqs), calc_freq());

    const freq_t all_freq = std::accumulate(freqs.begin(), freqs.end(), freq_t(), merge_freq());
    const int total = std::accumulate(all_freq.begin(), all_freq.end(), 0, count_total());

    freqv_t all_freq2;
    all_freq2.reserve(all_freq.size());

    std::copy(all_freq.begin(), all_freq.end(), std::back_inserter(all_freq2));
    std::sort(all_freq2.begin(), all_freq2.end(), sorter<freqv_t>());

    std::for_each(all_freq2.begin(), all_freq2.end(), freq_print_each<freqv_t>(total));
  }
  catch (const std::exception& e) {
    std::cerr << e.what() << std::endl;
  }

  return 0;
}