前言
博主参加了NOI2020
的同步赛,赛场上原本每天的t1都稳到手,无奈一题被卡常,一题输出输反了,最后得到了65pts的好成绩。d1t2想到了dp再优化,奈何手速慢了(老年选手)没得到分。两天t1都没看清数据范围每天都丢了1h花在无意义的思考上。值得反思。
总而言之,今年的NOI能过的题代码复杂度都不大,比较偏向于考察思维。
美食家
首先很容易想到DP
这里\(y_j\)根据题意当\(i=t_j\)且\(v=x_j\)时产生的额外贡献。
仔细观察\(w\leqslant 5\),这点很重要。容易联想到动态DP,这里用一个\(wn\times wn\)的矩阵维护转移,因为\(\max\)对加法满足结合律,且只有\(k\leqslant 200\)项转移比较特殊,其他的直接预处理出来连续的一段转移矩阵即可,复杂度\(\mathcal O((nw)^3k\log n)\),无法通过。
对于转移矩阵\(A\),维护\(A^{2^i}\),将一段连续的转移分解并且往向量上乘,复杂度降为\(\mathcal O((nw)^3\log n+(nw)^2k\log n)\),可以通过本题。注意常数。
#include <bits/stdc++.h>
#define rep(i, a, b) for (int i = a, i##end = b; i <= i##end; ++i)
#define per(i, a, b) for (int i = a, i##end = b; i >= i##end; --i)
#define rep0(i, a) for (int i = 0, i##end = a; i < i##end; ++i)
#define per0(i, a) for (int i = (int)a-1; ~i; --i)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define chkmax(a, b) a = max(a, b)
#define chkmin(a, b) a = min(a, b)
#define x first
#define y second
#define enter putchar('\n')
typedef long long ll;
inline int read() {
int w = 0, f = 1; char c;
while (!isdigit(c = getchar())) c == '-' && (f = -1);
while (isdigit(c)) w = w*10+(c^48), c = getchar();
return w * f;
}
const int maxL = 255;
const int maxn = 55;
const int maxk = 205;
const int inf = 1<<30;
struct Matrix {
ll a[maxL][maxL];
int n, m;
ll *operator [] (int i) { return a[i]; }
};
Matrix operator * (Matrix A, Matrix B) {
Matrix C; C.n = A.n, C.m = B.m;
rep0(i, A.n) rep0(j, B.m) C[i][j] = -1ll*inf*inf;
rep0(k, A.m)
rep0(i, A.n)
rep0(j, B.m)
C[i][j] = max(C[i][j], A[i][k] + B[k][j]);
return C;
}
int n, m, T, k;
int c[maxn], L, t[maxk], lst[maxk];
Matrix A[32], B[maxk], x;
bool cmp(int a, int b) { return t[a] < t[b]; }
void jump(int d) {
rep(j, 0, L)
if (d & (1<<j)) x = A[j]*x;
}
int main() {
n = read(), m = read(), T = read(), k = read();
L = log2(T);
rep0(i, n) c[i] = read();
A[0].n = A[0].m = 5*n;
rep0(i, A[0].n)
rep0(j, A[0].m)
A[0][i][j] = i == j+n ? 0 : -1ll*inf*inf;
rep(i, 1, m) {
int u = read()-1, v = read()-1, w = read()-1;
A[0][v][w*n+u] = c[v];
}
rep(i, 1, L) A[i] = A[i-1]*A[i-1];
rep(i, 1, k) {
t[lst[i] = i] = read(); int x = read()-1, y = read();
memcpy(&B[i], &A[0], sizeof(Matrix));
rep0(j, 5*n) if (B[i][x][j] != -inf) B[i][x][j] += y;
}
std::sort(lst+1, lst+k+1, cmp);
x.n = 5*n, x.m = 1;
rep0(i, x.n) x[i][0] = i ? -inf : 0;
rep(i, 1, k) {
jump(t[lst[i]] - t[lst[i-1]] - 1);
x = B[lst[i]]*x;
}
jump(T - t[lst[k]]);
printf("%lld", max(-1ll, x[0][0] + c[0]));
return 0;
}
命运
(咕咕咕)
时代的眼泪
不会正解,只会部分分
制作菜品
超现实树
翻修道路
这题也不会,只会暴力