Skip to content

3700. Number of ZigZag Arrays II

SourceWeekly Contest 469 Q4DifficultyHardRating2435

Description

You are given three integers n, l, and r.

A ZigZag array of length n is defined as follows:

  • Each element lies in the range [l, r].
  • No two adjacent elements are equal.
  • No three consecutive elements form a strictly increasing or strictly decreasing sequence.

Return the total number of valid ZigZag arrays.

Since the answer may be large, return it modulo 109 + 7.

A sequence is said to be strictly increasing if each element is strictly greater than its previous one (if exists).

A sequence is said to be strictly decreasing if each element is strictly smaller than its previous one (if exists).

 

Example 1:

Input: n = 3, l = 4, r = 5

Output: 2

Explanation:

There are only 2 valid ZigZag arrays of length n = 3 using values in the range [4, 5]:

  • [4, 5, 4]
  • [5, 4, 5]

Example 2:

Input: n = 3, l = 1, r = 3

Output: 10

Explanation:

​​​​​​​There are 10 valid ZigZag arrays of length n = 3 using values in the range [1, 3]:

  • [1, 2, 1], [1, 3, 1], [1, 3, 2]
  • [2, 1, 2], [2, 1, 3], [2, 3, 1], [2, 3, 2]
  • [3, 1, 2], [3, 1, 3], [3, 2, 3]

All arrays meet the ZigZag conditions.

 

Constraints:

  • 3 <= n <= 109
  • 1 <= l < r <= 75​​​​​​​

Solutions

Solution 1

Thinking

\(n\) can reach \(10^9\), so a length-by-length DP is impossible; the value range has length \(m=r-l+1\le 75\), which keeps the state space small. A zigzag array forbids equal neighbors and any strictly monotone triple, which means the comparison direction must flip at every step. We therefore encode a state by the last value and last direction (\(2m\) states). The transition is independent of the remaining length, so we build a \(2m\times 2m\) matrix, raise it to the \((n-1)\)-st power, and multiply by the length-\(1\) initial vector.

 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
class Solution:
    def zigZagArrays(self, n: int, l: int, r: int) -> int:
        mod = 10**9 + 7
        m = r - l + 1
        size = 2 * m
        trans = [[0] * size for _ in range(size)]
        for x in range(m):
            for y in range(x):
                trans[y][m + x] = 1
        for x in range(m):
            for y in range(x + 1, m):
                trans[m + y][x] = 1

        def mul_mat(a, b):
            res = [[0] * size for _ in range(size)]
            for i in range(size):
                for k in range(size):
                    if a[i][k] == 0:
                        continue
                    aik = a[i][k]
                    for j in range(size):
                        if b[k][j]:
                            res[i][j] = (res[i][j] + aik * b[k][j]) % mod
            return res

        def mul_vec(mat, vec):
            res = [0] * size
            for i in range(size):
                s = 0
                for j in range(size):
                    s = (s + mat[i][j] * vec[j]) % mod
                res[i] = s
            return res

        power = [[int(i == j) for j in range(size)] for i in range(size)]
        exp = n - 1
        while exp:
            if exp & 1:
                power = mul_mat(power, trans)
            trans = mul_mat(trans, trans)
            exp >>= 1
        init = [1] * size
        return sum(mul_vec(power, init)) % mod
 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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
class Solution {
    private static final long MOD = 1_000_000_007L;

    public int zigZagArrays(int n, int l, int r) {
        int m = r - l + 1;
        int size = 2 * m;

        long[][] trans = new long[size][size];
        for (int x = 0; x < m; x++) {
            for (int y = 0; y < x; y++) {
                trans[y][m + x] = 1;
            }
        }

        // down[x] -> up[y] where y > x
        for (int x = 0; x < m; x++) {
            for (int y = x + 1; y < m; y++) {
                trans[m + y][x] = 1;
            }
        }

        long[][] power = matrixPow(trans, n - 1);

        long[] init = new long[size];
        for (int i = 0; i < m; i++) {
            init[i] = 1;
            init[m + i] = 1;
        }

        long[] result = multiply(power, init);

        long ans = 0;
        for (long v : result) {
            ans = (ans + v) % MOD;
        }

        return (int) ans;
    }

    private long[] multiply(long[][] mat, long[] vec) {
        int n = mat.length;
        long[] res = new long[n];

        for (int i = 0; i < n; i++) {
            long sum = 0;
            for (int j = 0; j < n; j++) {
                sum = (sum + mat[i][j] * vec[j]) % MOD;
            }
            res[i] = sum;
        }

        return res;
    }

    private long[][] matrixPow(long[][] mat, long exp) {
        int n = mat.length;

        long[][] res = new long[n][n];
        for (int i = 0; i < n; i++) {
            res[i][i] = 1;
        }

        while (exp > 0) {
            if ((exp & 1) == 1) {
                res = multiply(res, mat);
            }

            mat = multiply(mat, mat);
            exp >>= 1;
        }

        return res;
    }

    private long[][] multiply(long[][] a, long[][] b) {
        int n = a.length;
        long[][] res = new long[n][n];

        for (int i = 0; i < n; i++) {
            for (int k = 0; k < n; k++) {
                if (a[i][k] == 0) continue;

                long aik = a[i][k];

                for (int j = 0; j < n; j++) {
                    if (b[k][j] == 0) continue;

                    res[i][j] = (res[i][j] + aik * b[k][j]) % MOD;
                }
            }
        }

        return res;
    }
}
 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
69
70
71
72
73
74
75
76
77
78
class Solution {
public:
    int zigZagArrays(int n, int l, int r) {
        const int mod = 1e9 + 7;
        int m = r - l + 1;
        int size = 2 * m;
        vector<vector<long long>> trans(size, vector<long long>(size));
        for (int x = 0; x < m; ++x) {
            for (int y = 0; y < x; ++y) {
                trans[y][m + x] = 1;
            }
        }
        for (int x = 0; x < m; ++x) {
            for (int y = x + 1; y < m; ++y) {
                trans[m + y][x] = 1;
            }
        }
        auto power = matrixPow(trans, n - 1, mod);
        vector<long long> init(size, 1);
        auto result = multiply(power, init, mod);
        long long ans = 0;
        for (long long v : result) {
            ans = (ans + v) % mod;
        }
        return ans;
    }

private:
    vector<long long> multiply(vector<vector<long long>>& mat, vector<long long>& vec, int mod) {
        int n = mat.size();
        vector<long long> res(n);
        for (int i = 0; i < n; ++i) {
            long long sum = 0;
            for (int j = 0; j < n; ++j) {
                sum = (sum + mat[i][j] * vec[j]) % mod;
            }
            res[i] = sum;
        }
        return res;
    }

    vector<vector<long long>> multiply(
        vector<vector<long long>>& a, vector<vector<long long>>& b, int mod) {
        int n = a.size();
        vector<vector<long long>> res(n, vector<long long>(n));
        for (int i = 0; i < n; ++i) {
            for (int k = 0; k < n; ++k) {
                if (a[i][k] == 0) {
                    continue;
                }
                long long aik = a[i][k];
                for (int j = 0; j < n; ++j) {
                    if (b[k][j] == 0) {
                        continue;
                    }
                    res[i][j] = (res[i][j] + aik * b[k][j]) % mod;
                }
            }
        }
        return res;
    }

    vector<vector<long long>> matrixPow(vector<vector<long long>>& mat, long long exp, int mod) {
        int n = mat.size();
        vector<vector<long long>> res(n, vector<long long>(n));
        for (int i = 0; i < n; ++i) {
            res[i][i] = 1;
        }
        while (exp > 0) {
            if (exp & 1) {
                res = multiply(res, mat, mod);
            }
            mat = multiply(mat, mat, mod);
            exp >>= 1;
        }
        return res;
    }
};
 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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
func zigZagArrays(n int, l int, r int) int {
    const mod = 1_000_000_007
    m := r - l + 1
    size := 2 * m
    trans := make([][]int, size)
    for i := range trans {
        trans[i] = make([]int, size)
    }
    for x := 0; x < m; x++ {
        for y := 0; y < x; y++ {
            trans[y][m+x] = 1
        }
    }
    for x := 0; x < m; x++ {
        for y := x + 1; y < m; y++ {
            trans[m+y][x] = 1
        }
    }
    power := matrixPow(trans, n-1, mod)
    init := make([]int, size)
    for i := range init {
        init[i] = 1
    }
    result := mulVec(power, init, mod)
    ans := 0
    for _, v := range result {
        ans = (ans + v) % mod
    }
    return ans
}

func mulVec(mat [][]int, vec []int, mod int) []int {
    n := len(mat)
    res := make([]int, n)
    for i := 0; i < n; i++ {
        sum := 0
        for j := 0; j < n; j++ {
            sum = (sum + mat[i][j]*vec[j]) % mod
        }
        res[i] = sum
    }
    return res
}

func mulMat(a, b [][]int, mod int) [][]int {
    n := len(a)
    res := make([][]int, n)
    for i := range res {
        res[i] = make([]int, n)
    }
    for i := 0; i < n; i++ {
        for k := 0; k < n; k++ {
            if a[i][k] == 0 {
                continue
            }
            aik := a[i][k]
            for j := 0; j < n; j++ {
                if b[k][j] == 0 {
                    continue
                }
                res[i][j] = (res[i][j] + aik*b[k][j]) % mod
            }
        }
    }
    return res
}

func matrixPow(mat [][]int, exp int, mod int) [][]int {
    n := len(mat)
    res := make([][]int, n)
    for i := range res {
        res[i] = make([]int, n)
        res[i][i] = 1
    }
    for exp > 0 {
        if exp&1 == 1 {
            res = mulMat(res, mat, mod)
        }
        mat = mulMat(mat, mat, mod)
        exp >>= 1
    }
    return res
}

Comments