https://www.acmicpc.net/problem/12878


Blocks


n=1일때와 n=2일때 어떻게 전개되는지를 생각해보니 금방 풀 수 있었다.


상태

경우의 수

빨강

노랑

추가->

a

c

2a+b+c

a

b

a

b

d

a+2b+d

b

a

b

c

a

a+2c+d

c

d

c

d

b

b+c+2d

d

c

d



따라서 n개일 때 경우의 수들에 행렬을 곱해 n=1일 때 경우의 수들을 구할 수 있다.


그래서 결국 4*4 행렬을 구하는 문제로 바뀌는데, n이 십억까지므로, 2^x승들의 행렬들을 미리 구하는 분할정복으로 풀 수 있다.


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
#include <iostream>
#include <math.h>
#include <string.h>
using namespace std;
 
#define m 10007
typedef long long ll;
 
ll n;
ll origin[4][4= 
{2,1,1,0},
{1,2,0,1},
{1,0,2,1},
{0,1,1,2} };
 
ll mat[30][4][4];
 
int main() {
    memcpy(mat[0], origin, sizeof(origin));
 
    cin >> n;
    ll tmp[4][4];
    int d = 1;
    while ((ll(1<< d) <= n) {
        for (int i = 0; i < 4++i) {
            for (int j = 0; j < 4++j) {
                ll t = 0;
                for (int k = 0; k < 4++k) {
                    t = (t + (mat[d - 1][i][k] * mat[d - 1][k][j]) % m) % m;
                }
                tmp[i][j] = t;
            }
        }
 
        memcpy(mat[d++], tmp, sizeof(tmp));
    }
 
    int dd = 0;
    int arr[4= { 1,0,0,0 };
    while ((ll(1<< dd) <= n) {
        int tmp[4];
        if (n & (ll(1<< dd)) {
            for (int i = 0; i < 4++i) {
                tmp[i] = 0;
                for (int j = 0; j < 4++j)
                    tmp[i] = (tmp[i] + (mat[dd][i][j] * arr[j]) % m) % m;
            }
 
            memcpy(arr, tmp, sizeof(tmp));
        }
        dd++;
    }
 
    cout << arr[0] % m;
}
cs


+ Recent posts