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;
}

命運

(咕咕咕)

時代的眼淚

不會正解,只會部分分

製作菜品

超現實樹

翻修道路

這題也不會,只會暴力

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