CSP-S 2022题解

1 \(Holiday\)

观察到 \(k \le 100\),很自然地想到 \(O(\dfrac{nmk}{64})\) 预处理出所有点在转 \(k\) 次车后可以到达的点集。

考虑枚举 \(B, C\),计算可行的 \(A, D\) 中的最大值。

预处理 \(1\) 号点与其他点中 \(k\) 可达点集的前 \(3\) 大值,复杂度 \(O(n^2)\)

简单合并 \(6\) 个值即可。

时间复杂度 \(O(\dfrac{nmk}{64} + n^2)\)

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <cstdlib>
#include <cmath>
#include <deque>
#include <bitset>
using namespace std;
#define pii pair<int,int>
#define mp make_pair
const int N = 2505, M = 1e4 + 10, K = 105;
#define int long long
int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
int n, m, k;
int a[N];
vector<int> v[N];
int maxn[N], maxx[N], maxxx[N];
bitset<N> b[N][K];
signed main()
{
    n = read(), m = read(), k = read();
    for (int i = 2; i <= n; i++) a[i] = read();
    for (int i = 1; i <= m; i++)
    {
        int x = read(), y = read();
        v[x].push_back(y), v[y].push_back(x);
        b[x][0].set(y), b[y][0].set(x);
    }
    for (int p = 1; p <= k; p++)
    {
        for (int i = 1; i <= n; i++)
        {
            b[i][p] = b[i][p - 1];
            int siz = v[i].size();
            for (int j = 0; j < siz; j++)
            {
                int x = v[i][j];
                b[i][p] |= b[x][p - 1];
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (i == j) continue;
            if (b[i][k][j] == 0 || b[1][k][j] == 0) continue;
            if (a[j] > a[maxn[i]]) maxxx[i] = maxx[i], maxx[i] = maxn[i], maxn[i] = j;
            else if (a[j] == a[maxn[i]]) maxxx[i] = maxx[i], maxx[i] = j;
            else if (a[j] > a[maxx[i]]) maxxx[i] = maxx[i], maxx[i] = j;
            else if (a[j] == a[maxx[i]]) maxxx[i] = j;
            else if (a[j] > a[maxxx[i]]) maxxx[i] = j;
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (i == j) continue;
            if (!b[i][k][j]) continue;
            int A = 0, B = 0;
            if (maxn[i] != j) A = maxn[i];
            else if (maxx[i] != j) A = maxx[i];
            else if (maxxx[i] != j) A = maxxx[i];
            if (maxn[j] != i && maxn[j] != A) B = maxn[j];
            else if (maxx[j] != i && maxx[j] != A) B = maxx[j];
            else if (maxxx[j] != i && maxxx[j] != A) B = maxxx[j];
            if (A && B) ans = max(ans, a[i] + a[j] + a[A] + a[B]);
        }
    }
    printf("%lld\n", ans);
    return 0;
}

2 \(Game\)

简单分类讨论。

如果 \(L\)\([l_1, r_1]\) 内的正数,\(Q\)\([l_2, r_2]\) 内最小值最优。

此时 \(Q\) 所选的数一定,故 \(L\) 选择的要么是最大的正数,要么是最小的正数。

如果 \(L\)\(0\),那么 \(Q\) 无论选什么结果都是 \(0\)

如果 \(L\)\([l_1, r_1]\) 内的负数,\(Q\)\([l_2, r_2]\) 内最大值最优。

此时 \(Q\) 所选的数仍然一定,故 \(L\) 选择的要么是最大的负数,要么是最小的负数。

维护 \(6\)\(st\) 表,分别表示 \(a\) 中区间最大正数,区间最小正数,区间最大负数,区间最小负数和 \(b\) 中区间最大值和区间最小值即可。

时间复杂度 \(O(n \log n + m\log m + q)\)

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;
#define int long long
int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
int n, m, q;
int a[N], b[N], sum[N];
struct stb1
{
    int st[N][20];
    void init(int f)
    {
        if (f == 1)
        {
            for (int i = 1; i <= n; i++) st[i][0] = (a[i] > 0) ? a[i] : -1;
            for (int j = 1; j <= 19; j++)
                for (int i = 1; i + (1 << j) - 1 <= n; i++)
                    st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
        }
        else if (f == 2)
        {
            for (int i = 1; i <= n; i++) st[i][0] = (a[i] > 0) ? a[i] : 1e9 + 1;
            for (int j = 1; j <= 19; j++)
                for (int i = 1; i + (1 << j) - 1 <= n; i++)
                    st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
        }
        else if (f == 3)
        {
            for (int i = 1; i <= n; i++) st[i][0] = (a[i] < 0) ? a[i] : -1e9 - 1;
            for (int j = 1; j <= 19; j++)
                for (int i = 1; i + (1 << j) - 1 <= n; i++)
                    st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
        }
        else
        {
            for (int i = 1; i <= n; i++) st[i][0] = (a[i] < 0) ? a[i] : 1;
            for (int j = 1; j <= 19; j++)
                for (int i = 1; i + (1 << j) - 1 <= n; i++)
                    st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
        }
    }
    int query(int l, int r, int f)
    {
        int x = log2(r - l + 1);
        if (f == 1 || f == 3) return max(st[l][x], st[r - (1 << x) + 1][x]);
        return min(st[l][x], st[r - (1 << x) + 1][x]);
    }
}T1, T2, T3, T4;
struct stb2
{
    int st[N][20];
    void init(int f)
    {
        for (int i = 1; i <= m; i++) st[i][0] = b[i];
        if (f == 1)
        {
            for (int j = 1; j <= 19; j++)
                for (int i = 1; i + (1 << j) - 1 <= m; i++)
                    st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
        }
        else
        {
            for (int j = 1; j <= 19; j++)
                for (int i = 1; i + (1 << j) - 1 <= m; i++)
                    st[i][j] = min(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
        }
    }
    int query(int l, int r, int f)
    {
        int x = log2(r - l + 1);
        if (f == 1) return max(st[l][x], st[r - (1 << x) + 1][x]);
        return min(st[l][x], st[r - (1 << x) + 1][x]);
    }
}T5, T6;
signed main()
{
    n = read(), m = read(), q = read();
    for (int i = 1; i <= n; i++) a[i] = read(), sum[i] = sum[i - 1] + (a[i] == 0);
    for (int i = 1; i <= m; i++) b[i] = read();
    T1.init(1); T2.init(2); T3.init(3); T4.init(4), T5.init(1), T6.init(2);
    for (int i = 1; i <= q; i++)
    {
        int l1 = read(), r1 = read(), l2 = read(), r2 = read();
        int res = ll(-1e18) - 1;
        int A = T1.query(l1, r1, 1), B = T2.query(l1, r1, 2), C = T3.query(l1, r1, 3), D = T4.query(l1, r1, 4);
        int E = T5.query(l2, r2, 1), F = T6.query(l2, r2, 2);
        if (sum[r1] - sum[l1 - 1] > 0) res = 0;
        if (A != -1) res = max(res, A * F);
        if (B != 1e9 + 1) res = max(res, B * F);
        if (C != -1e9 - 1) res = max(res, C * E);
        if (D != 1) res = max(res, D * E);
        printf("%lld\n", res);
    }
    return 0;
}

3 \(Galaxy\)

人类智慧题。

观察到一个性质:如果所有节点都可以实现连续穿越,那么所有据点都可以实现反击。

这是因为如果每个点都存在出边,那么一直沿出边走一定可以回到某个访问过的点。

问题转化为了判断所有节点的出度 \(deg_i\) 是否都为 \(1\)

考虑给每个节点随机赋予一个权值 \(a_i\),当前状态值为 \(\sum_{i = 1}^n \limits deg_ia_i\)

将判断是否成立的条件设为:当前状态值是否等于 \(\sum_{i = 1}^n \limits a_i\)

根据感性理解,这个算法的正确率非常高。

于是我们只用记录 \(S_i\) 表示所有当前存在指向 \(i\) 的边的点的 \(a_i\) 之和,操作时简单计算当前状态值即可。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <cstdlib>
#include <cmath>
#include <deque>
using namespace std;
#define pii pair<int,int>
#define mp make_pair
const int N = 5e5 + 10;
typedef long long ll;
#define int long long
int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
int n, m, tot, ans, sum;
int a[N], head[N], ver[N * 2], last[N * 2], S[N], cur[N];
void add(int x, int y)
{
    ver[++tot] = y;
    last[tot] = head[x];
    head[x] = tot;
}
signed main()
{
    srand(time(NULL));
    n = read(), m = read();
    for (int i = 1; i <= n; i++) a[i] = rand() % (ll)(1e10) + 1, sum += a[i];
    for (int i = 1; i <= m; i++)
    {
        int u = read(), v = read();
        S[v] += a[u]; cur[v] += a[u]; ans += a[u];
    }
    int q = read();
    for (int i = 1; i <= q; i++)
    {
        int opt = read();
        if (opt == 1)
        {
            int u = read(), v = read();
            cur[v] -= a[u]; ans -= a[u];
        }
        if (opt == 2)
        {
            int u = read();
            ans -= cur[u];
            cur[u] = 0;
        }
        if (opt == 3)
        {
            int u = read(), v = read();
            cur[v] += a[u]; ans += a[u];
        }
        if (opt == 4)
        {
            int u = read();
            ans += S[u] - cur[u];
            cur[u] = S[u];
        }
        if (ans == sum) puts("YES");
        else puts("NO");
    }
    return 0;
}

4 \(Transmit\)

简单矩阵乘法。

\(k = 1\) 时,询问为路径上点权之和,简单 \(LCA\) 即可。

\(k = 2\) 时,将路径看作一个序列。设 \(f_i\) 表示 \(i\) 强制选择时,前 \(i\) 个主机花费时间的最小值。

显然有 \(f_i = \min \{f_{i - 1}, f_{i - 2}\} + a_i\)

对于 \(n, q \le 2000\) 以及数据随机的部分分,设 \(len\) 为期望链长,\(O(q \times len)\) 的暴力 \(dp\) 复杂度是可以接受的。

容易发现,\(min\)\(+\) 存在矩阵乘法。

设初始矩阵为 \(\begin{bmatrix} f_i & f_{i+1} \end{bmatrix}\),那么转移矩阵为 \(\begin{bmatrix} INF & a_{i+2} \\ 0 & a_{i+2} \end{bmatrix}\)

也就是说:

\[\begin{bmatrix} f_i & f_{i+1} \end{bmatrix} \otimes \begin{bmatrix} INF & a_{i+2} \\ 0 & a_{i+2} \end{bmatrix} = \begin{bmatrix} f_{i+1} & f_{i +2} \end{bmatrix} \]

其中 \(\otimes\) 表示新定义的矩阵乘法,满足对于 \(a \times b\) 的矩阵 \(A\)\(b \times c\) 的矩阵 \(B\),有 \(A \otimes B = C \to C_{i, j} = \min_{k = 1}^b \limits A_{i, k} + B_{k, j}\)

容易证明,该矩阵乘法满足结合律 \(A\otimes B\otimes C = A \otimes (B \otimes C)\),但值得注意的是,它并不满足交换律。

有了结合律后,我们可以先将路径上第 \(i + 2\) 及以后项元素的转移矩阵依次相乘,再与初始矩阵相乘。

维护路径上所有转移矩阵的乘积可以用倍增实现。具体地,设 \(g_{x, i}\) 表示 \(x\) 开始,向上 \(2^i\) 个祖先的转移矩阵从下到上的乘积。查询时直接倍增乘在一起即可。

需要注意的是,矩阵乘法并不满足交换律,也就是说我们需要记录 \(G_{x, i}\) 表示 \(x\) 开始,向上 \(2^i\) 个祖先的转移矩阵从上到下的乘积,查询时倒着倍增。

\(k = 3\) 时,不能简单地令 \(f_i = \min \{f_{i - 2}, f_{i-1}, f_i\}\),因为可能有一步跳出链后沿着距离路径为 \(1\) 的若干点连续跳跃,最后跳回链上。

比如当图为 \(1 - 2, 2 - 3, 3 - 4, 3 - 5, 5 - 6, 5 - 7, 7 - 8\) 时,\(1 \to 8\) 的路径可以由 \(1\to 4 \to 6\to 8\) 组成。

容易发现,只有在跳到距离链为 \(1\) 的点上的时候可能更优,否则相当于白走了一个点。

修改一下我们的状态:\(f_{i, 0/1}\) 表示 \(i\) 强制选择\(/\)\(i\) 相邻的不在链上的点强制选择,花费时间的最小值。

\(b_i\) 为与 \(i\) 相邻且不在链上的点的权值的最小值,那么有转移:

\(f_{i, 0} = \min\{f_{i - 1, 0}, f_{i - 2, 0}, f_{i-3, 0}, f_{i-2, 1}\} + a_i, f_{i, 1} = \min \{f_{i - 2,0 }, f_{i - 1, 1}\} + b_i\)

此时的初始矩阵为 \(\begin{bmatrix} f_{i, 0} & f_{i, 1} & f_{i + 1, 0} & f_{i + 1, 1} & f_{i + 2, 0} & f_{i + 2, 1}\end{bmatrix}\),转移矩阵为:

\(\begin{bmatrix} INF & INF & INF & INF & a_{i + 3} & INF \\ INF & INF & INF & INF & INF & INF \\ 0 & INF & INF & INF & a_{i + 3} & b_{i + 3} \\ INF & 0 & INF & INF & a_{i + 3} & INF\\ INF & INF & 0 & INF & a_{i + 3} & INF \\ INF & INF & INF & 0 & INF & b_{i + 3} \end{bmatrix}\)

维护方法与之前类似。

但此时有了新的问题:占用的空间太大了。

\(\dfrac{6 \times 6 \times 2 \times 10^5 \times 18 \times 2 \times 8}{1024 \times 1024} \approx 1977 MB\)

此时再次观察上面的转移矩阵,发现有一整行的转移都是 \(INF\)

于是我们抛弃掉 \(f_{i, 1}\),将矩阵改写为 \(5\times 5\) 的。

\(\begin{bmatrix} INF & INF & INF & a_{i + 3} & INF \\ 0 & INF & INF & a_{i + 3} & b_{i + 3} \\ INF & INF & INF & a_{i + 3} & INF \\ INF & 0 & INF & a_{i + 3} & INF \\ INF & INF & 0 & INF & b_{i + 3} \end{bmatrix}\)

此时的空间为 \(\dfrac{5 \times 5 \times 2 \times 10^5 \times 18 \times 2 \times 8}{1024 \times 1024} \approx 1373 MB\)

还是超过了空间限制,但是注意到 \(G\) 数组其实没有必要,在第一次利用完 \(g\) 后将询问离线,将 \(G\) 的信息存储在 \(g\) 内再跑一遍即可。

此时的空间为 \(\dfrac{5 \times 5 \times 2 \times 10^5 \times 18 \times 8}{1024 \times 1024} \approx 686 MB\)

时间复杂度 \(O(5^3n\log n + 5^3m\log n)\)

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <cstdlib>
#include <cmath>
#include <deque>
using namespace std;
#define pii pair<int,int>
#define mp make_pair
const int N = 2e5 + 1;
typedef long long ll;
int read()
{
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
int n, Q, k, tot, cnt;
int head[N], ver[N * 2], last[N * 2], a[N], b[N], f[N][18], dep[N], c[N], u[N], v[N];
ll dp[N][3];
pii Cur[N];
struct Matrix
{
    ll a[5][5];
    void init() {for (int i = 0; i < 5; i++) for (int j = 0; j < 5; j++) a[i][j] = 0x3f3f3f3f3f3f3f3f;}
    void one() {init(); for (int i = 0; i < 5; i++) a[i][i] = 0;}
    void print()
    {
        for (int i = 0; i < 5; i++)
        {
            for (int j = 0; j < 5; j++) 
            {
                cout << a[i][j] << ' ';
            }
            cout << endl;
        }
    }
}g[N][18];
Matrix ans[N];
Matrix operator *(const Matrix &a, const Matrix &b)
{
    Matrix res; res.init();
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            for (int p = 0; p < 5; p++)
                res.a[i][j] = min(res.a[i][j], a.a[i][p] + b.a[p][j]);
        }
    }
    return res;
}
void add(int x, int y)
{
    ver[++tot] = y;
    last[tot] = head[x];
    head[x] = tot;
}
int lca(int x, int y)
{
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 17; i >= 0; i--) if (dep[f[x][i]] >= dep[y]) x = f[x][i];
    if (x == y) return x;
    for (int i = 17; i >= 0; i--) {if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];}
    return f[x][0];
}
void dfs(int x, int fa)
{
    dep[x] = dep[fa] + 1;
    for (int i = head[x]; i; i = last[i])
    {
        int y = ver[i];
        if (y == fa) continue;
        f[y][0] = x;
        for (int j = 1; j <= 17; j++) f[y][j] = f[f[y][j - 1]][j - 1];
        g[y][0].init();
        g[y][0].a[1][0] = 0; g[y][0].a[3][1] = 0; g[y][0].a[4][2] = 0;
        if (k == 3) g[y][0].a[0][3] = g[y][0].a[2][3] = a[y], g[y][0].a[1][4] = g[y][0].a[4][4] = b[y];
        if (k >= 2) g[y][0].a[1][3] = a[y];
        g[y][0].a[3][3] = a[y];
        for (int j = 1; j <= 17 && f[y][j - 1]; j++) g[y][j] = g[y][j - 1] * g[f[y][j - 1]][j - 1];
        dfs(y, x);
    }
}
void dfs2(int x, int fa)
{
    for (int i = head[x]; i; i = last[i])
    {
        int y = ver[i];
        if (y == fa) continue;
        for (int j = 1; j <= 17 && f[y][j - 1]; j++) g[y][j] = g[f[y][j - 1]][j - 1] * g[y][j - 1];
        dfs2(y, x);
    }
}
Matrix get2(int x, int y)
{
    Matrix res;
    res.one();
    for (int i = 17; i >= 0; i--) if (dep[f[x][i]] >= dep[y]) res = res * g[x][i], x = f[x][i];
    return res;
}
Matrix get(int x, int y)
{
    Matrix res;
    res.one();
    int cnt2 = 0;
    for (int i = 17; i >= 0; i--) if (dep[f[x][i]] >= dep[y]) Cur[++cnt2] = mp(x, i), x = f[x][i];
    for (int i = cnt2; i >= 1; i--) res = res * g[Cur[i].first][Cur[i].second];
    return res;
}
signed main()
{
    n = read(), Q = read(), k = read();
    for (int i = 1; i <= n; i++) a[i] = read();
    for (int i = 1; i < n; i++)
    {
        int u = read(), v = read();
        add(u, v); add(v, u);
    }
    for (int x = 1; x <= n; x++)
    {
        b[x] = 0x3f3f3f3f;
        for (int i = head[x]; i; i = last[i])
            b[x] = min(b[x], a[ver[i]]);
    }
    g[1][0].init();
    g[1][0].a[1][0] = 0; g[1][0].a[3][1] = 0; g[1][0].a[4][2] = 0;
    if (k == 3) g[1][0].a[0][3] = g[1][0].a[2][3] = a[1], g[1][0].a[1][4] = g[1][0].a[4][4] = b[1];
    if (k >= 2) g[1][0].a[1][3] = a[1];
    g[1][0].a[3][3] = a[1];
    dfs(1, 0);
    for (int i = 1; i <= Q; i++)
    {
        u[i] = read(), v[i] = read();
        int L = lca(u[i], v[i]);
        if (dep[u[i]] - dep[L] < dep[v[i]] - dep[L]) swap(u[i], v[i]);
        if (dep[u[i]] - dep[L] <= 3) continue;
        int p = u[i];
        for (int j = 1; j <= 3; j++) p = f[p][0];
        ans[i] = get2(p, L) * g[L][0];
    }
    dfs2(1, 0);
    for (int i = 1; i <= Q; i++)
    {
        int L = lca(u[i], v[i]);
        if (dep[u[i]] - dep[L] < dep[v[i]] - dep[L]) swap(u[i], v[i]);
        if (dep[u[i]] - dep[L] <= 3)
        {
            int pos; cnt = 0;
            while (u[i] != L) c[++cnt] = u[i], u[i] = f[u[i]][0];
            c[++cnt] = L; pos = cnt;
            while (v[i] != L) c[++cnt] = v[i], v[i] = f[v[i]][0];
            for (int j = pos + 1; j <= cnt; j++)
                if (j > (cnt - (j - pos) + 1)) swap(c[j], c[cnt - (j - pos) + 1]);
            dp[1][0] = a[c[1]]; dp[1][1] = 0x3f3f3f3f3f3f3f3f;
            for (int j = 2; j <= cnt; j++) dp[j][0] = dp[j][1] = 0x3f3f3f3f3f3f3f3f;
            for (int j = 2; j <= cnt; j++)
            {
                for (int p = 1; p <= k; p++) if (j > p) dp[j][0] = min(dp[j][0], dp[j - p][0]);
                if (k == 3 && j > 2)
                {
                    dp[j][0] = min(dp[j][0], dp[j - 2][1]);
                    dp[j][1] = min(dp[j][1], dp[j - 1][1]);
                    dp[j][1] = min(dp[j][1], dp[j - 2][0]);
                }
                dp[j][0] += a[c[j]]; dp[j][1] += b[c[j]];
            }
            printf("%lld\n", dp[cnt][0]);
            continue;
        }
        cnt = 0;
        for (int j = 1; j <= 3; j++) c[++cnt] = u[i], u[i] = f[u[i]][0];
        dp[1][0] = a[c[1]]; dp[1][1] = 0x3f3f3f3f3f3f3f3f;
        for (int j = 2; j <= cnt; j++) dp[j][0] = dp[j][1] = 0x3f3f3f3f3f3f3f3f;
        for (int j = 2; j <= cnt; j++)
        {
            for (int p = 1; p <= k; p++) if (j > p) dp[j][0] = min(dp[j][0], dp[j - p][0]);
            if (k == 3 && j > 2)
            {
                dp[j][0] = min(dp[j][0], dp[j - 2][1]);
                dp[j][1] = min(dp[j][1], dp[j - 1][1]);
                dp[j][1] = min(dp[j][1], dp[j - 2][0]);
            }
            dp[j][0] += a[c[j]]; dp[j][1] += b[c[j]];
        }
        ans[i] = ans[i] * get(v[i], L);

        Matrix cur;
        cur.init(); cur.a[0][0] = dp[1][0], cur.a[0][1] = dp[2][0], cur.a[0][2] = dp[2][1], cur.a[0][3] = dp[3][0], cur.a[0][4] = dp[3][1];
        cur = cur * ans[i];
        printf("%lld\n", cur.a[0][3]);
    }
    return 0;
}

欢迎关注我的公众号

posted @ 2022-10-31 09:44  David24  阅读(511)  评论(6编辑  收藏  举报