NOI2020专题

前言

博主参加了NOI2020同步赛,赛场上原本每天的t1都稳到手,无奈一题被卡常,一题输出输反了,最后得到了65pts的好成绩。d1t2想到了dp再优化,奈何手速慢了(老年选手)没得到分。两天t1都没看清数据范围每天都丢了1h花在无意义的思考上。值得反思。

总而言之,今年的NOI能过的题代码复杂度都不大,比较偏向于考察思维。

美食家

首先很容易想到DP

\[f_{i,v}=\max\{f_{i-w,u}\}+c_v[+y_j] \]

这里\(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;
}

命运

(咕咕咕)

时代的眼泪

不会正解,只会部分分

制作菜品

超现实树

翻修道路

这题也不会,只会暴力

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章