//别看,测试样例一多就过不了
//先在这放着,啥时候有空再改
//如下按照我的想法没有实现版
//哈哈哈哈哈哈哈哈哈 精神状态良好
#include <iostream>
#include <cstring>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <queue>
using namespace std;
struct TreeNode {
char zimu;
int weight;
int parent;
int leftchild;
int rightchild;
int hti;
char huffcode[1000];
TreeNode() {};
TreeNode(int w, char z = '\0', int hti = -1, int p = 0, int l = 0, int r = 0) {
weight = w;
zimu = z;
parent = p;
leftchild = l;
rightchild = r;
}
};
class HuffmanTree {
public:
HuffmanTree(int num) {
char temp;
for (int i = 0; i < num; i++) {
cin >> temp;
zimu[temp - 65]++;
}
}
void CreateTree();
void CreateTreecode();
void Select(int k, int& s1, int& s2);
void Print();
private:
TreeNode* HT;
int n=0;
int zimu[26] = { 0 };
//char** HC;
};
struct cmp
{
bool operator()(const TreeNode* a, const TreeNode* b)const
{
return a->weight > b->weight;
}
};
priority_queue<TreeNode, vector<TreeNode>, cmp> minHeap;
short comp( const TreeNode& a, const TreeNode& b) {
return a.weight > b.weight;
}
int main() {
int num;
cin >> num;
HuffmanTree Tree(num);
Tree.CreateTree();
Tree.CreateTreecode();
Tree.Print();
}
void HuffmanTree::CreateTree()
{
int cnt = 0;
for (int i = 0; i < 26; i++) {
if (zimu[i] > 0) {
cnt++;
}
}
n = cnt;
//cout << n << endl;
if (cnt <= 1)
return;
int m = 2 * n- 1;
HT = new TreeNode[m + 1];
int k = 1;
for (int i = 1; i < m + 1; i++) {
HT[i].parent = 0;
HT[i].leftchild = 0;
HT[i].rightchild = 0;
}
for (int i = 0; i < 26; i++) {
if (zimu[i] > 0) {
TreeNode temp(zimu[i],i+65,k);
HT[k] = temp;
minHeap.push(temp);
//cout << HT[k].zimu << " " << HT[k].weight << endl;
k++;
}
}
int s1;
int s2;
for (int i = n+1; i <=m; i++) {
//cout << " i" << i-1 << endl;
Select(i - 1, s1, s2);
//cout << s1 << " " << s2 << endl;
HT[s1].parent = i;
HT[s2].parent = i;
HT[i].leftchild = s1;
HT[i].rightchild = s2;
HT[i].weight = HT[s1].weight + HT[s2].weight;
HT[i].hti = i;
minHeap.push(HT[i]);
}
/*
cout << "字符 权 父母 左 右" << endl;
for (int i = 1; i <=m; i++) {
cout << HT[i].zimu << " " << HT[i].weight << " " << HT[i].parent << " " << HT[i].leftchild
<< " " << HT[i].rightchild << endl;
}
*/
}
void HuffmanTree::CreateTreecode()
{
//HC = new char* [n + 1];
char* cd = new char[n];
cd[n - 1] = '\0';
for (int i = 1; i <= n; i++) {
int start = n - 1;
int c = i;
int f = HT[i].parent;
while (f != 0) {
start--;
if (HT[f].leftchild == c)
cd[start] = '0';
else
cd[start] = '1';
c = f;
f = HT[f].parent;
}
for (int j = 0; j < start; j++) {
HT[i].huffcode[j] = '\0';
}
for (int j = start; j < n - 1; j++) {
//cout << cd[j];
HT[i].huffcode[j] = cd[j];
//cout << HT[i].huffcode[j];
}
HT[i].huffcode[n - 1] = '\0';
}
//delete cd;
//for (int i = 1; i < n; i++) {
// HT[i].huffcode = HC[i];
//}
}
void HuffmanTree::Select(int k, int& s1, int& s2)
{
int fmin=1;
int smin=1;
TreeNode min1 = minHeap.top();
minHeap.pop();
TreeNode min2 = minHeap.top();
minHeap.pop();
s1 = min1.hti;
s2=min2.hti;
/*
int pos1, pos2;
for (int i = 0; i <= k; i++) {
if (HT[i].parent == 0) {
if (HT[i].weight < min1) {
min2 = min1;
pos2 = pos1;
min1 = HT[i].weight;
pos1 = i;
}
else if (HT[i].weight < min2) {
min2 = HT[i].weight;
pos2 = i;
}
}
}
s1 = pos1;
s2 = pos2;
*/
for (int i = 1; i <=k; i++) {
if (HT[i].parent == 0) {
fmin = i;
smin = i;
//cout <<" f s "<< fmin << " " << smin << endl;
break;
}
}
for (int i = 1; i <= k; i++) {
int temp;
int flag = 0;
if (HT[i].weight < HT[fmin].weight&&HT[i].parent==0) {
smin = fmin;
fmin = i;
}
else if (HT[i].weight < HT[smin].weight&&HT[i].parent==0) {
smin = i;
}
if (fmin == smin && HT[i].weight == HT[fmin].weight && i != fmin&&HT[i].parent==0) {
smin = i;
}
}
if (fmin == smin) {
for (int i = 1; i <= k; i++) {
if (HT[i].parent == 0&&i!=fmin) {
smin = i;
}
}
}
s1 = fmin;
s2 = smin;
//cout << " s1 s2 " << fmin << " " << smin << endl;
}
void HuffmanTree::Print()
{
sort(HT+1,HT+n+1,comp);
for (int i = 1; i <= n; i++) {
cout << HT[i].zimu << " " << HT[i].weight << " ";
int j = 0;
for (int j = 0; j < n - 1; j++) {
if (HT[i].huffcode[j] != '\0')
cout << HT[i].huffcode[j];
}
cout << endl;
}
}