[NOI2020]美食家
随便写写吧…
显然方程式 \(f_{t,u}\) 表示 \(t\) 时间在 \(u\) 的最大贡献。
\(f_{t,u} = \max\{f_{t-w,v} + c_u\}\)。
看到这范围绝对是矩阵快速幂了…
等等边权不为\(1\)?
那就构造一个长度为 \(5 \times n\) 的向量嘛,然后每过一个时间就会移动。
我们令 \(id(i,j)\) 为 \(position\) 为 \(i\) 的时候,当前时间为 \(6-j\) 的状态。
然后转移矩阵是考虑 \(id(i,j+1) \to id(i,j)\) 的,然后连上边,注意有重边,如果没有注意的话会有奇奇怪怪的问题。
如果有一条 \(\{u, v, w\}\) 的边,我们考虑
base[0][id(u, 6 - w)][id(v, 5)] = c[v];
实际意义是满足方程式。(
然后就可以转移了。
预处理 \(\log_2 10^9 = 30\) 个矩阵,向量乘矩阵的复杂度是 \((5n)^2\) 的。
所以复杂度是 \(((5n)^3 + (5n)^2k)\times \log_2 t\)。
#include <bits/stdc++.h>
#define FOR(i, x, y) for (int i = x; i <= y; i++)
#define ROF(i, x, y) for (int i = x; i >= y; i--)
int n, m, T, k;
int c[51];
struct buf { int t, x, y; } q[201];
struct Matrix {
long long a[251][251];
Matrix() { memset(a, 0xc0, sizeof(a)); }
long long* operator[](int x) { return a[x]; }
} base[31];
struct Vector {
long long a[251];
Vector() { memset(a, 0xc0, sizeof(a)); }
long long& operator[](int x) { return a[x]; }
} answer;
int lim;
Matrix mul(Matrix a, Matrix b) {
Matrix c;
FOR(i, 1, lim)
FOR(j, 1, lim)
FOR(k, 1, lim)
c[i][j] = std::max(c[i][j], a[i][k] + b[k][j]);
return c;
}
Vector mul(Vector a, Matrix b) {
Vector c;
FOR(i, 1, lim)
FOR(j, 1, lim)
c[i] = std::max(c[i], a[j] + b[j][i]);
return c;
}
int id(int x, int y) { return x + (y - 1) * n; }
int main() {
#ifdef LOCAL
freopen("testdata.txt", "r", stdin);
#endif
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
std::cin >> n >> m >> T >> k;
lim = n * 5;
FOR(i, 1, n) std::cin >> c[i];
FOR(i, 1, m) {
int u, v, w;
std::cin >> u >> v >> w;
base[0][id(u, 6 - w)][id(v, 5)] = c[v];
}
FOR(i, 1, k) {
int t, x, y;
std::cin >> t >> x >> y;
q[i] = {t, x, y};
}
std::sort(q + 1, q + k + 1, [](buf x, buf y) { return x.t < y.t; });
FOR(i, 1, n) FOR(j, 1, 4) base[0][id(i, j + 1)][id(i, j)] = 0;
FOR(i, 1, 30) base[i] = mul(base[i - 1], base[i - 1]);
answer[id(1, 5)] = c[1];
FOR(i, 1, k) {
int t = q[i].t - q[i - 1].t;
FOR(j, 0, 30) if (t >> j & 1) answer = mul(answer, base[j]);
answer[id(q[i].x, 5)] += q[i].y;
}
int t = T - q[k].t;
FOR(j, 0, 30) if (t >> j & 1) answer = mul(answer, base[j]);
std::cout << std::max(answer[id(1, 5)], -1ll) << '\n';
return 0;
}