Loading

「刷题记录」LOJ/一本通提高篇 区间类动态规划

「石子合并」

题目传送门:石子合并
状态:\(dp(i, j)\) : 第 \(i\) 堆到第 \(j\) 堆合并的最优解
\(dp_{max}(i, j) = \max(dp(i, j), dp(i, k) + dp(k + 1, j) + sum(i, j))\)
\(dp_{min}(i, j) = \min(dp(i, j), dp(i, k) + dp(k + 1, j) + sum(i, j))\)

点击查看代码
/*
  date: 2022.8.31
  worked by yi_fan0305
 */
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

const int N = 500;
const int inf = ~(1 << 31);
int n, maxn, minn = inf;
int w[N], dp_max[N][N], dp_min[N][N], qsum[N];

inline ll read() {
	ll x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

int main() {
	n = read();
	memset(dp_min, 127, sizeof dp_min);
	memset(dp_max, 128, sizeof dp_max);
	for (int i = 1; i <= n; ++i) {
		w[i] = read();
		w[i + n] = w[i];
		dp_max[i][i] = dp_min[i][i] = 0;
		qsum[i] = qsum[i - 1] + w[i];
	}
	for (int i = n + 1; i <= (n << 1); ++i) {
		dp_max[i][i] = dp_min[i][i] = 0;
		qsum[i] = qsum[i - 1] + w[i];
	}
	for (int len = 1; len < n; ++len) {
		for (int i = 1; i + len <= (n << 1); ++i) {
			int j = i + len;
			for (int k = i; k < j; ++k) {
				dp_max[i][j] = max(dp_max[i][j], dp_max[i][k] + dp_max[k + 1][j] + qsum[j] - qsum[i - 1]);
				dp_min[i][j] = min(dp_min[i][j], dp_min[i][k] + dp_min[k + 1][j] + qsum[j] - qsum[i - 1]);
			}
		}
	}
	for (int i = 1; i <= n; ++i) {
		maxn = max(maxn, dp_max[i][i + n - 1]);
		minn = min(minn, dp_min[i][i + n - 1]);
//		cout << dp_max[i][i + n - 1] << " " << dp_min[i][i + n - 1] << endl;
	}
	printf("%d\n%d", minn, maxn);
	return 0;
}

「能量项链」

题目传送门:能量项链
状态:\(dp(i, j)\) : 第 \(i\) 颗能量石到第 \(j\) 颗能量石合并释放的最大能量
\(dp(i, j) = max(dp(i, j), dp(i, k) + dp(k + 1, j) + m_i \times r_k \times r_j)\)

点击查看代码
/*
  date: 2022.8.31
  worked by yi_fan0305
 */
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;

const int N = 310;
int n, ans;
int w[N], he[N], ti[N], dp[N][N];

inline ll read() {
	ll x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

int main() {
	n = read();
	for (int i = 1; i <= n; ++i) {
		w[i] = read();
		w[i + n] = w[i];
	}
	for (int i = 1; i <= (n << 1); ++i) {
		he[i] = w[i];
		ti[i] = w[i + 1];
	}
	ti[n << 1] = he[1];
	for (int len = 1; len < n; ++len) {
		for (int i = 1; i + len <= (n << 1); ++i) {
			int j = i + len;
			for (int k = i; k < j; ++k) {
				dp[i][j] = max(dp[i][j], dp[i][k] + dp[k + 1][j] + he[i] * ti[k] * ti[j]);
			}
		}
	}
	for (int i = 1; i <= n; ++i) {
		ans = max(ans, dp[i][i + n - 1]);
	}
	printf("%d\n", ans);
	return 0;
}

「凸多边形的划分」

题目传送门:凸多边形的划分
状态:\(dp(i, j)\) : 第 \(i\) 个点 到第 \(j\) 个点划分成三角形的最小乘积和
\(dp(i, j) = min(dp(i, j), dp(i, k) + dp(k, r) + a_i * a_k * a_r\)

点击查看代码
/*
  date: 2022.8.31
  worked by yi_fan0305
 */
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;

const int N = 110;
const ll inf = ~(1ll << 63);
int n;
__int128 ans = 1e30;
__int128 w[N], ji[N], qsum[N], dp[N][N];

inline __int128 read() {
	__int128 x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

void print(__int128 x) {
	if (x < 0) {
		x = -x;
		putchar('-');
	}
	if (x > 9)
		print(x / 10);
	putchar(x % 10 + '0');
}

int main() {
	n = read();
	for (int i = 1; i <= n; ++i) {
		w[i] = read();
		w[i + n] = w[i];
		dp[i][i] = dp[i + n][i + n] = 0;
	}
	for (int i = 1; i <= (n << 1); ++i) {
		for (int j = i + 2; j <= (n << 1); ++j) {
			dp[i][j] = 1e30;
		}
	}
	for (int len = 2; len < n; ++len) {
		for (int l = 1; l + len <= (n << 1); ++l) {
			int r = l + len;
			for (int k = l + 1; k < r; ++k) {
				dp[l][r] = min(dp[l][r], dp[l][k] + dp[k][r] + w[l] * w[k] * w[r]);
			}
		}
	}
	for (int i = 1; i <= n; ++i) {
		ans = min(ans, dp[i][i + n - 1]);
	}
	print(ans);
	return 0;
}

「括号配对」

题目传送门:括号配对
状态:\(dp(i, j)\)\(l - r\) 区间内能配对起来的符号个数

\[dp(i, j) = max\begin{cases} dp(i, j) = dp(i + 1, j - 1) + 2 && w_i 与 w_j 能配对起来\\ dp(i, j) = max(dp(i + 1, j), dp(i, j - 1)) && w_i 与 w_j 不能配对起来\\ \end{cases} \]

\(dp(i, j) = max(dp(i, j), dp(i, k) + dp(k + 1, j))\)

点击查看代码
/*
  date: 2022.9.1
  worked by yi_fan0305
 */
#include <iostream>
#include <cstdio>
#include <string>
#include <cmath>
#include <stack>
using namespace std;
typedef long long ll;

int dp[110][110];
string str;
stack<char> st;

inline ll read() {
	ll x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

int main() {
	cin >> str;
	int siz = str.size();
	for (int len = 1; len < siz; ++len) {
		for (int l = 0; l + len < siz; ++l) {
			int r = l + len;
			if  ((str[l] == '[' && str[r] == ']') || (str[l] == '(' && str[r] == ')'))
				dp[l][r] = dp[l + 1][r - 1] + 2;
			else 
				dp[l][r] = max(dp[l + 1][r], dp[l][r - 1]);
			for (int k = l; k < r; ++k) {
				dp[l][r] = max(dp[l][r], dp[l][k] + dp[k + 1][r]);
			}
		}
	}
	printf("%d\n", siz - dp[0][siz - 1]);
	return 0;
}

「分离与合体」

题目传送门:分离与合体
状态:\(dp(i, j)\) : \(l - r\) 区间内拿到金钥匙的最大价值和
\(dp(i, j) = max(dp(i, j), dp(i, k) + dp(k + 1, j) + (w_i + w_j) \times w_k)\)
用广搜来输出答案

点击查看代码
/*
  date: 2022.9.1
  worked by yi_fan0305
 */
#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;

const int N = 310;
int n;
int w[N], dp[N][N], qsum[N], ans[N][N];

struct node {
	int l, r;
} tmp;

inline ll read(){
	ll x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

void print(int l, int r) {
	queue<node> q;
	tmp.l = l;
	tmp.r = r;
	q.push(tmp);
	while(!q.empty()) {
		node u = q.front();
		q.pop();
		if(u.l == u.r)
			continue;
		printf("%d ", ans[u.l][u.r]);
		tmp.l = u.l, tmp.r = ans[u.l][u.r];
		q.push(tmp);
		tmp.l = ans[u.l][u.r] + 1, tmp.r = u.r;
		q.push(tmp);
	}
}

int main() {
	n = read();
	for (int i = 1; i <= n; ++i) {
		w[i] = read();
		qsum[i] = qsum[i - 1] + w[i];
	}
	for (int len = 1; len < n; ++len) {
		for (int l = 1; l + len <= n; ++l) {
			int r = l + len;
			for (int k = l; k < r; ++k) {
				if (dp[l][k] + dp[k + 1][r] + (w[l] + w[r]) * w[k] > dp[l][r]) {
					dp[l][r] = max(dp[l][r], dp[l][k] + dp[k + 1][r] + (w[l] + w[r]) * w[k]);
					ans[l][r] = k;
				}
			}
		}
	}
	printf("%d\n", dp[1][n]);
	print(1, n);
	return 0;
}

「矩阵取数游戏」

题目传送门:矩阵取数游戏
状态:\(dp(i, j)\) :\(i - j\) 区间内取 \(m\) 个数的最大价值

\[dp(i, j) = max\begin{cases} dp(i, j) = dp(i - 1, j) + point(m - j + i - 1) * w_{i - 1}\\ dp(i, j) = dp(i, j + 1) + point(m - j + i - 1) * w_{j + 1}\\ \end{cases} \]

点击查看代码
/*
  date: 2022.9.1
  worked by yi_fan0305
 */
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

int n, m;
__int128 ans;
__int128 w[100], dp[110][110], point[110];

inline __int128 read() {
	__int128 x = 0;
	int fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? ~x + 1 : x;
}

void pre() {
	point[0] = 1;
	for (int i = 1; i <= m; ++i) {
		point[i] = point[i - 1] * 2;
	}
}

void print(__int128 x) {
	if(x < 0) {
		x = -x;
		putchar('-');
	}
	if(x > 9)	print(x / 10);
	putchar(x % 10 + '0');
}

int main() {
	n = read(), m = read();
	pre();
	for (int k = 1; k <= n; ++k) {
		for (int j = 1; j <= m; ++j) {
			w[j] = read();
		}
		memset(dp, 0, sizeof dp);
		for (int i = 1; i <= m; ++i) {
			for (int j = m; j >= i; --j) {
				dp[i][j] = max(dp[i][j], dp[i - 1][j] + point[m - j + i - 1] * w[i - 1]);
				dp[i][j] = max(dp[i][j], dp[i][j + 1] + point[m - j + i - 1] * w[j + 1]);
			}
		}
		__int128 maxn = 0;
		for (int i = 1; i <= m; ++i) {
			maxn = max(maxn, dp[i][i] + point[m] * w[i]);
		}
		ans += maxn;
	}
	print(ans);
	return 0;
}
posted @ 2022-09-02 10:12  yi_fan0305  阅读(42)  评论(0编辑  收藏  举报