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

「石子合并」#

题目传送门:石子合并
状态:dp(i,j) : 第 i 堆到第 j 堆合并的最优解
dpmax(i,j)=max(dp(i,j),dp(i,k)+dp(k+1,j)+sum(i,j))
dpmin(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)+mi×rk×rj)

点击查看代码
/*
  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)+aiakar

点击查看代码
/*
  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)lr 区间内能配对起来的符号个数

dp(i,j)=max{dp(i,j)=dp(i+1,j1)+2wiwjdp(i,j)=max(dp(i+1,j),dp(i,j1))wiwj

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) : lr 区间内拿到金钥匙的最大价值和
dp(i,j)=max(dp(i,j),dp(i,k)+dp(k+1,j)+(wi+wj)×wk)
用广搜来输出答案

点击查看代码
/*
  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) :ij 区间内取 m 个数的最大价值

dp(i,j)=max{dp(i,j)=dp(i1,j)+point(mj+i1)wi1dp(i,j)=dp(i,j+1)+point(mj+i1)wj+1

点击查看代码
/*
  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;
}

作者:yifan0305

出处:https://www.cnblogs.com/yifan0305/p/16648869.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

转载时还请标明出处哟!

posted @   yi_fan0305  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示