Триомино
Сколькими способами можно замостить прямоугольник $2 × n$ триоминошками? Триомино — это геометрическая фигура, составленная из трех квадратов, соединяющихся между собой вдоль полного ребра. Есть только две возможных триоминошки:
Например, замостить прямоугольник $2 × 3$ можно только тремя различными способами. Поскольку ответ может быть достаточно большим, искомое количество способов следует вычислять по модулю $10^6$.
Входные данные
Первая строка содержит количество тестов $t$ ($1 \leqslant t \leqslant 100$). Каждая из следующих $t$ строк содержит значение $n$ ($0 < n < 10^9$).
Выходные данные
Для каждого теста в отдельной строке выведите количество способов, которыми можно замостить прямоугольник $2 × n$. Результат следует выводить по модулю $10^6$.
Тесты
№ |
Входные данные |
Выходные данные |
1 | 3 3 4 6 |
3 0 11 |
2 | 4 12 15 21 9 |
153 571 7953 41 |
Код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
import java.util.*; import java.lang.*; import java.io.*; class Main { static long MOD=1000000; static long[][] multiply(long[][] v1) { long[][] ans=new long[2][2]; long x00 = v1[0][0]; long x01 = v1[0][1]; long x10 = v1[1][0]; long x11 = v1[1][1]; long res00, res01, res10, res11; res00 = ((x00 * x00) % MOD + (x10 * x01) % MOD) % MOD; res01 = ((x00 * x01) % MOD + (x01 * x11) % MOD) % MOD; res10 = ((x10 * x00) % MOD + (x10 * x11) % MOD) % MOD; res11 = ((x10 * x01) % MOD + (x11 * x11) % MOD) % MOD; ans[0][0]=(res00+MOD)%MOD; ans[0][1]=(res01-MOD)%MOD; ans[1][0]=(res10+MOD)%MOD; ans[1][1]=(res11-MOD)%MOD; return ans; } static long[][] pow_mod(long[][] v, int p) { if (p == 1) return v; //if ((p % 2) == 0) return multiply((pow_mod(v, p / 2))); } public static void main (String[] args) { Scanner in = new Scanner(System.in); int t=in.nextInt(); for (int i = 0; i < t; i++) { int n=in.nextInt(); if (n % 3!=0) { System.out.println(0); } else { n /= 3; int p = 2; long a1 = 1, a2 = 1; while (n > 0) { if ((n & 1)==1) { long[][] a = { {4,-1},{1,0} }; a = pow_mod(a, p / 2); long tmp1 = a1; long tmp2 = a2; a1 = (tmp1 * a[0][0]) % MOD + (tmp2 * ((a[0][1] + MOD) % MOD)) % MOD; a2 = (tmp1 * a[1][0]) % MOD + (tmp2 * ((a[1][1] + MOD) % MOD)) % MOD; } p *= 2; n >>= 1; } a1=a1%MOD; System.out.println(a1); } } } } |
Решение
Если n нацело не делится на $3$, то выводится ноль,в ином случае данная задача решается через рекуррентную формулу $a_n=4*a_{n-1}-a_{n-2}$. Но из-за слишком больших чисел мы не можем использовать данную формулу просто так, поэтому мы воспользуемся быстрым вычислением членов рекуррентной последовательности через матрицы. Надо умножать матрицу
$\begin{pmatrix}
4&-1 \\\
1&0 \\\
\end{pmatrix}$ в степени $p$(где $p$ равна двойке в степени номера единицы в двоичной записи числа ${{n}\over{3}}$) на матрицу $\begin{pmatrix}
1\\\
1\\\
\end{pmatrix}$ каждый раз, когда встречается единица в двоичной записи числа ${{n}\over{3}}$. На выход подается первое число вектора $2 × 1$.
Ссылки
Условие задачи на e-olymp
Код программы на ideone