[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;
}
posted @ 2020-08-26 15:16  _Isaunoya  阅读(215)  评论(0编辑  收藏  举报