public class MappingABC {
final int MOD = 1000 * 1000 * 1000 + 7;
int[][] forbidden; // 'x' can be mapped to a letter 'y' only if forbidden[x][y] = 0
int[] total = new int[4]; // total[x] = how many numbers have 'x' possible letters
int[][] my_pow;
void computePow() {
my_pow = new int[total.length][forbidden.length+1];
for(int c = 0; c < total.length; ++c)
for(int i = 0; i <= forbidden.length; ++i) {
if(i == 0)
my_pow[c][i] = 1;
else
my_pow[c][i] = (int) ((long) my_pow[c][i-1] * c % MOD);
}
}
int toAnswer() {
int r = 1;
for(int c = 0; c < total.length; ++c)
r = (int) ((long) r * my_pow[c][total[c]] % MOD);
return r;
}
void clear() {
for(int i = 0; i < forbidden.length; ++i)
}
int countLetters(int x) {
int letters = 0;
for(int i = 0; i < 3; ++i)
if(forbidden[x][i] == 0)
++letters;
return letters;
}
void forget(int x) { --total[countLetters(x)]; }
void remind(int x) { ++total[countLetters(x)]; }
void add(int x, int y) { // 'x' can't be mapped to a letter 'y'
forget(x);
++forbidden[x][y];
remind(x);
}
void sub(int x, int y) { // cancel add()
forget(x);
--forbidden[x][y];
remind(x);
}
public int countStrings(int[] t) {
int n = t.length;
int MAX_VAL = 0;
for(int i = 0; i < n; ++i) {
MAX_VAL = max(MAX_VAL, t[i]);
--t[i];
}
boolean appears[] = new boolean[MAX_VAL];
for(int i = 0; i < MAX_VAL; ++i)
appears[i] = false;
for(int x : t)
appears[x] = true;
forbidden = new int[MAX_VAL][3];
computePow();
int answer = 0;
final int A = 0, B = 1, C = 2;
for(int rep = 0; rep < 2; ++rep) {
boolean NO_C = rep == 1; // in the second run of the loop
// we don't allow letters 'C' at the end
for (int a0 = 0; a0 < n; ++a0) {
clear();
for(int i = 0; i < MAX_VAL; ++i)
if(appears[i])
++total[3]; // it can be mapped to any of 3 letters
for (int i = 0; i < a0; ++i)
add(t[i], A); // no 'A'
add(t[a0], B); add(t[a0], C); // first 'A'
if (NO_C)
for (int i = a0 + 1; i < n; ++i)
add(t[i], C); // no 'C'
for (int b0 = a0 + 1; b0 < n; ++b0) {
int memo = answer;
if (NO_C)
sub(t[b0], C); // cancel
add(t[b0], A); add(t[b0], C); // first 'B'
if (NO_C)
answer = (answer - toAnswer() + MOD) % MOD;
else
answer = (answer + toAnswer()) % MOD;
sub(t[b0], A); sub(t[b0], C); // cancel
add(t[b0], B); // no 'B'
// System.out.println(NO_C + " " + a0 + " " + b0 + " ans=" + (answer - memo));
}
}
}
return answer;
}
}