题意

n 个数,初始全为 1。有 3 种操作:

  1. 将任意一个数 aa+50
  2. 将任意一个数 aa+20
  3. 将任意一个数 aa×2

给出每种操作的个数,你可以以任意顺序执行任意操作。

求最多执行多少个操作,使得操作结束后任意 ai100

思路

定义 dpi,j,k,l 表示考虑前 i 个数,执行了 j1 操作,k2 操作,l3 操作,ai 的最小值。

状态转移方程(类似于完全背包的转移):

dpi,j,k,l=min{dpi,j1,k,l+50,dpi,j,k1,l+20,dpi,j,k,l1×2}

dpi,j,k,l=1(dpi1,j,k,l100)

为确保不会溢出,转移时可以先判断是否 100 再转移。

状态数:O(nm3),转移:O(1),总时间复杂度:O(nm3)

空间可以使用滚动数组优化,O(m3)

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 305;
int n, m, ans;
int a, b, c;
int dp[2][301][301][301];
bool ok[2][301][301][301];
int main() {
	freopen("horse.in", "r", stdin);
	freopen("horse.out", "w", stdout);
	cin >> n >> m;
	cin >> a >> b >> c;
	dp[0][0][0][0] = 1, ok[0][0][0][0] = 1;
	for (int i = 1, p = 1; i <= n; i ++, p ^= 1) {
		for (int j = 0; j <= a; j ++) {
			for (int k = 0; k <= b; k ++) {
				for (int l = 0; l <= c; l ++) {
					dp[p][j][k][l] = 1e9, ok[p][j][k][l] = 0;
					if (ok[p ^ 1][j][k][l]) dp[p][j][k][l] = 1;
					if (j && ok[p][j - 1][k][l]) dp[p][j][k][l] = min(dp[p][j][k][l], dp[p][j - 1][k][l] + 50);
					if (k && ok[p][j][k - 1][l]) dp[p][j][k][l] = min(dp[p][j][k][l], dp[p][j][k - 1][l] + 20);
					if (l && ok[p][j][k][l - 1]) dp[p][j][k][l] = min(dp[p][j][k][l], dp[p][j][k][l - 1] * 2);
					ok[p][j][k][l] = (dp[p][j][k][l] <= 100);
					if (ok[p][j][k][l]) ans = max(ans, j + k + l);
				}
			}
		}
	}
	cout << ans << "\n";
	return 0;
}
posted @   maniubi  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示