Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

出現頻度操作

有限数列の変換操作に出現頻度操作というものがあります。数列 $S = \{s_1, s_2,... s_n\}$ の変換結果は同じ長さの数列となります。その結果を $C = \{c_1,c_2, ..., c_n\}$ とすると、 $c_i$ は数列 $S$ における $s_i$ の個数を表します。

例えば $S = \{3,4,1,5,9,2,6,5,3\}$ ならば $C = {2,1,1,2,1,1,1,2,2}$ となります。さらにこの数列 $C$ に出現頻度操作を行うと $P = \{4,5,5,4,5,5,5,4,4\}$ を得ます。この数列は出現頻度操作で変わることがありません。このような数列 $P$ を数列 $S$ の不動点と呼びます。どのような数列に対しても出現頻度操作を繰り返せば、その不動点を求めることが出来るということが知られています。

下の例は出現頻度操作の手順を示したものです。1 行目を数列 $S$ 、2 行目を数列 $C$、最終行を数列 $P$ とします。数列 $S$ の最初の要素($s_1 = 2$) と同じ数は 3 個あるので数列 $C$ の最初の要素 $c_1$ は 3、次の要素 ($s_2 = 7$) と同じ数は 2 個あるので $c_2 = 2$、といった具合に個数を数え $c_i$ を求めていきます。

数列の長さ $n$ と数列 $S$ を入力し、不動点の数列 $P$ および、$P$ を得るために実行した出現頻度操作の最小の回数を出力するプログラムを作成してください。

Input

複数のデータセットが与えられます。各データセットは以下の形式で与えられます。

$n$

$s_1$ $s_2$ ... $s_n$

1 行目に数列の長さを表す整数 $n$ ($n \leq 12$) が与えられます。２行目に数列 $S$ の要素を表す整数　$s_i$ ($1 \leq s_i \leq 100$) が空白区切りで与えられます。

入力は０一つの行で終わります。データセットの数は 200 を超えません。

Output

各データセットについて、１行目に出現頻度操作の最小の実行回数(整数)、２行目に対応する不動点の数列 $P$ の要素 $p_1$, $p_2$, ..., $p_n$ を空白区切りで出力してください。

Sample Input

10
4 5 1 1 4 5 12 3 5 4
0

Output for the Sample Input

3
6 6 4 4 6 6 4 4 6 6

Solution in JavaScript (judge verdict: Accepted)

"use strict";

var util = require("util"),
    puts = util.puts,
    p = util.print,
    cin = parseInput();

function isFixed(nums, prev) {
    if ( prev === undefined || nums.length != prev.length ) return false;
    for ( var i = 0; i < nums.length; i++ ) {
        if ( nums[i] != prev[i] ) return false;
    }
    return true;
}

function toFrequency(nums) {
    var memo = [],
        ret = [];

    for ( var i = 0; i < nums.length; i++ ) {
        var n = nums[i],
            cnt = 1;

        if ( memo[n] === undefined ) {
            for ( var j = i + 1; j < nums.length; j++ ) {
                if ( n == nums[j] ) cnt++;
            }
            memo[n] = cnt;
        }
        ret[i] = memo[n];
    }
    return ret;
}

var n;

while( n = cin.nextInt() ) {
    var nums = [],
        prev = [],
        cnt = 0;

    while(n--) nums.push(cin.nextInt());

    while(true) {
        prev = nums.slice(0);
        nums = toFrequency(nums);

        if ( isFixed(nums, prev) ) break;
        cnt++;
    }

    puts(cnt);
    puts(nums.join(" "));
}


function parseInput(useSplitSpace) {
    var index = 0,
        ret = [],
        input = require("fs").readFileSync("/dev/stdin", "utf8"),
        inputs = input.replace(/\r/g, '').split("\n");

    useSplitSpace = useSplitSpace || true;

    // 入力を改行/空白で区切り平坦な配列に変換
    inputs.forEach(function(val) {
        if ( useSplitSpace && val !== "" ) {
            val.split(" ").forEach(function(el) {
                if ( el !== "" ) ret.push(el);
            });
        } else {
            ret.push(val);
        }
    });

    return {
        hasNext: function(val) {
            if ( typeof val === "undefined" ) {
                return typeof ret[index] !== "undefined";
            } else {
                return ret[index] === val;
            }
        },
        next: function() {
            if ( typeof ret[index+1] === "undefined" ) throw new RangeError("Index out of bounds at '" + index+1 + "'");
            return ret[index++];
        },
        nextNumber: function () {
            if ( !/^\d+$/.test(this.top()) ) throw new TypeError("'" + this.top() + "' cannot convet to Number");
            return +this.next();
        },
        nextInt: function() {
            return parseInt(this.nextNumber());
        },
        top: function() {
            return ret[index];
        },
        rewind: function() {
            index = 0;
        }
    };
}