• [NOI2020]美食家


    首先可以思考一下暴力,不难发现我们可以令 (dp_{i, j}) 表示在第 (i) 秒到达 (j) 的最大愉悦值,这样转移就十分显然了。那么如果 (k = 0),观察一下转移的方程:

    [dp_{i, j} = max_{k ightarrow j}{dp_{i - w_{k, j}, k} + c_j} ]

    如果 (w_{k, j} = 1) 那么这将会是一个经典的可优化问题,并将 (dp_{i - 1}) 看作一个矩阵,转移费用看成一个矩阵 (forall j ightarrow k, val_{j, k} = c_k),实际上这个过程是一个类似于矩乘的过程,即 (A imes B(i, j) = maxlimits_{k = 1} ^ {n}{A_{i, k} + B_{k, j}}) 为了能加速转移,下面我们来证明这个矩乘依然是满足结合律的。

    回忆一下原式矩乘的结合律是怎么证明的,即我们要证明 ((A imes B) imes C = A imes (B imes C)) 为了方便起见我们令三个矩阵的大小都为 (n imes n) 空的位置用 (0) 补齐是不会影响的,那么有:

    [egin{aligned} (A imes B) imes C(i, j) &= sumlimits_{k = 1} ^ n igg(sumlimits_{l = 1} ^ n A_{i, l} imes B_{l, k}igg) imes C_{k, j}\ &= sumlimits_{l = 1} ^ n sumlimits_{k = 1} ^ n A_{i, l} imes B_{l, k} imes C_{k, j}\ &= sumlimits_{k = 1} ^ n A_{i, k} sumlimits_{l = 1} ^ n B_{k, l} imes C_{l, j} = A imes (B imes C)(i, j) end{aligned} ]

    从上面的过程中可以看到,矩乘满足结合律的要求是满足分配律即 (igg(sumlimits_{l = 1} ^ n A_{i, l} imes B_{l, k}igg) imes C_{k, j}) 可以将里面的 (C_{k, j}) 乘进去。那么实际上 (max{a, b} + c = max{a + c, b + c}) 也是可以拉进去的,因此上面新定义的这个矩乘运算也是满足结合律的。所以这个新定义的矩乘也是可以使用矩阵快速幂加速的。于是我们现在的问题在于考虑如何让边权变为 (1),因为边权最大只有 (5),于是我们可以将每条边拆成 (w - 1) 个点,依次连起来即可,但是这样点数是 (n + 4m) 的,不足以通过本题。因为点数很小,因此我们可以直接将每个点拆成 (5) 个点,然后按照长度直接连边,将价值挂在最后一个点上即可。这样点数就是 (5n) 的,复杂度 (O((5n) ^ 3 log T)) 可以通过本题。

    再考虑 (k e 0) 的情况,实际上我们发现问题的改变本质在于转移矩阵在这 (k) 个点上变得不同,于是我们直接在这 (k) 个位置单独转移即可,复杂度 (O(k(5n) ^ 3 log T)) 但是这还是不能过题。但是可以发现的是在本题中我们是用一个向量乘一个矩阵,这个过程是 (O(n ^ 2)) 的,并且每次我们单独转移的部分实际上只需要 (dp_{t_i, x_i} += y_i) 即可,转移矩阵并没有变,那么我们可以事先将转移矩阵 (G)(G ^ 0, G ^ 2, G ^ 4, cdots G ^ {2 ^ i}, cdots) 预处理出来,每次单独转移的部分用向量 (dp_i) 去乘每个转移矩阵 (G ^ {2 ^ j}) 即可,那么这样预处理的复杂度为 (O((5n) ^ 3 log T)),转移的复杂度为 (O(k(5n) ^ 2 log T)),就可以通过本题了。

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i, l, r) for(int i = l; i <= r; ++i)
    #define dep(i, l, r) for(int i = r; i >= l; --i)
    const int N = 250 + 5;
    const long long inf = 100000000000000;
    int n, m, T, k, u, v, w, c[N];
    long long tmp;
    struct mat{
        long long g[N][N];
        void clear(){
            rep(i, 1, n) rep(j, 1, n) g[i][j] = -inf;
        }
    }tr, dp, f[N];
    struct node{
        int t, x, y;
    }a[N];
    int read(){
        char c; int x = 0, f = 1;
        c = getchar();
        while(c > '9' || c < '0'){ if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int P(int x, int y){
        return 5 * (x - 1) + y;
    }
    mat mul(mat a, mat b){
        mat c; c.clear();
        rep(k, 1, n) if(a.g[1][k] >= 0){
            rep(j, 1, n) if(b.g[k][j] >= 0) c.g[1][j] = max(c.g[1][j], a.g[1][k] + b.g[k][j]);
        } 
        return c;
    }
    mat Mul(mat a, mat b){
        mat c; c.clear(); 
        rep(i, 1, n) rep(k, 1, n) if(a.g[i][k] >= 0){
            rep(j, 1, n) if(b.g[k][j] >= 0) c.g[i][j] = max(c.g[i][j], a.g[i][k] + b.g[k][j]);
        } 
        return c;
    }
    mat Qpow(mat a, int b){
        mat ans = a; --b; // 注意这里
        while(b){
            if(b & 1) ans = Mul(ans, a);
            a = Mul(a, a), b >>= 1;
        }
        return ans;
    }
    bool cmp(node a, node b){
        return a.t < b.t;
    }
    void solve(int T, int x, int y){
        dep(i, 0, 29) if(T >= (1 << i)) dp = mul(dp, f[i]), T -= (1 << i);
        if(dp.g[1][P(x, 5)] >= 0) dp.g[1][P(x, 5)] += y; 
    }
    int main(){
        n = read(), m = read(), T = read(), k = read();
        rep(i, 1, n) c[i] = read();
        rep(i, 1, 5 * n) rep(j, 1, 5 * n) tr.g[i][j] = -inf;
        rep(i, 1, n) rep(j, 1, 4) tr.g[P(i, j)][P(i, j + 1)] = (j == 4 ? c[i] : 0);
        rep(i, 1, m) u = read(), v = read(), w = read(), tr.g[P(u, 5)][P(v, 5 - w + 1)] = (w == 1 ? c[v] : 0);
        rep(i, 1, k) a[i].t = read(), a[i].x = read(), a[i].y = read();
        n = 5 * n, f[0] = tr, a[++k].t = T, a[k].x = 1, a[k].y = 0;
        rep(i, 1, 29) f[i] = Mul(f[i - 1], f[i - 1]);
        sort(a + 1, a + k + 1, cmp);
        rep(i, 1, n) dp.g[1][i] = -inf;
        dp.g[1][5] = c[1];
        rep(i, 1, k) solve(a[i].t - a[i - 1].t, a[i].x, a[i].y);
        printf("%lld", dp.g[1][5] >= 0 ? dp.g[1][5] : -1);
        return 0;
    }
    
    GO!
  • 相关阅读:
    第二章 Flask——Flask中的request
    第一章 Flask——Flask简介
    第四章 Linux——Nginx环境部署指南
    众测平台
    jmeter进阶
    adb命令对app进行测试
    众测平台
    selenium
    java基础知识
    接口测试工具对比
  • 原文地址:https://www.cnblogs.com/Go7338395/p/13573990.html
Copyright © 2020-2023  润新知