首页 > 其他分享 >2022.12.24 动态规划练习

2022.12.24 动态规划练习

时间:2022-12-24 13:44:39浏览次数:61  
标签:24 原料 练习 样例 times leq Subtask 耐久度 2022.12

洛谷P5858 「SWTR-03」Golden Sword

题目背景

小 E 不幸在一场战斗中失去了他的金宝剑。

题目描述

制造一把金宝剑需要 \(n\) 种原料,编号为 \(1\) 到 \(n\),编号为 \(i\) 的原料的坚固值为 \(a_i\)。

炼金是很讲究放入原料的顺序的,因此小 E 必须按照 \(1\) 到 \(n\) 的顺序依次将这些原料放入炼金锅。

但是,炼金锅的容量非常有限,它最多只能容纳 \(w\) 个原料

所幸的是,每放入一个原料之前,小 E 可以从中取出一些原料,数量不能超过 \(s\) 个。

  • 我们定义第 \(i\) 种原料的耐久度为:放入第 \(i\) 种原料时锅内的原料总数(包括正在放入的原料) \(\times\ a_i\),则宝剑的耐久度为所有原料的耐久度之和。

小 E 当然想让他的宝剑的耐久度尽可能得大,这样他就可以带着它进行更多的战斗,请求出耐久度的最大值。

注:这里的“放入第 \(i\) 种原料时锅内的原料总数包括正在放入锅中的原料,详细信息请见样例。

输入格式

第一行,三个整数 \(n,w,s\)。

第二行,\(n\) 个整数 \(a_1,a_2,\dots,a_n\)。

输出格式

一行一个整数,表示耐久度的最大值。

样例 #1

样例输入 #1

5 3 3
1 3 2 4 5

样例输出 #1

40

样例 #2

样例输入 #2

5 3 3
1 -3 -2 4 5

样例输出 #2

21

样例 #3

样例输入 #3

7 4 2
-5 3 -1 -4 7 -6 5

样例输出 #3

17

样例 #4

样例输入 #4

5 3 1
-1 -3 -2 -4 -5

样例输出 #4

-15

提示

「样例说明」

  • 对于样例 1,一种可行的最优方案为:
    首先放进原料 1,此时锅内有 \(1\) 种原料,耐久度为 \(1\times a_1=1\times 1=1\)。
    再放进原料 2,此时锅内有 \(2\) 种原料,耐久度为 \(2\times a_2=2\times 3=6\)。
    再放进原料 3,此时锅内有 \(3\) 种原料,耐久度为 \(3\times a_3=3\times 2=6\)。
    取出原料 1,再放进原料 4,此时锅内有 \(3\) 种原料,耐久度为 \(3\times a_4=3\times 4=12\)。
    取出原料 4,再放进原料 5,此时锅内有 \(3\) 种原料,耐久度为 \(3\times a_5=3\times 5=15\)。
    最终答案为 \(1+6+6+12+15=40\)。
  • 对于样例 2,一种可行的最优方案为:
    放进原料 1,耐久度为 \(1\times 1=1\)。
    取出原料 1,放进原料 2,耐久度为 \(1\times (-3)=-3\)。
    放进原料 3,耐久度为 \(2\times (-2)=-4\)。
    放进原料 4,耐久度为 \(3\times 4=12\)。
    取出原料 2,放进原料 5,耐久度为 \(3\times 5=15\)。
    最终答案为 \(1+(-3)+(-4)+12+15=21\)。
  • 对于样例 3,一种可行的最优方案为:
    \(a_1+2a_2+2a_3+3a_4+4a_5+3a_6+4a_7=17\)。
  • 对于样例 4,一种可行的最优方案为:
    \(a_1+a_2+a_3+a_4+a_5=-15\)。

「数据范围与约定」

本题使用捆绑测试。

  • Subtask #1(15 points):\(n\leq 10\)。
  • Subtask #2(5 points):\(n\leq 100\),\(a_i\geq0\)。
  • Subtask #3(15 points):\(n\leq 300\)。
  • Subtask #4(15 points):\(s=w=n\)。
  • Subtask #5(5 points):\(a_i\geq 0\)。
  • Subtask #6(10 points):\(n\leq 2\times 10^3\)。
  • Subtask #7(10 points):\(s=1\)。
  • Subtask #8(25 points):无特殊限制。

对于 \(100\%\) 的数据,\(1 \leq s \leq w \leq n \leq 5\times 10^3\),\(|a_i| \leq 10^9\)。对于 Subtask \(i\) 有 \(|a_i|\leq 10^{i+1}\)。

「帮助/说明」

本题下发大样例,具体输入输出见 Big Sample 中的 gold01-08.in/gold01-08.out。提取码:757d。
文件名与 Subtask 编号一一对应。

「来源」

Sweet Round 03 D
idea & solution:ET2006。

解题思路

状态表示:\(f[i][j]\) 表示考虑前 \(i\) 个原料中的某些放入且总数为 \(j\) 的耐久度集合,要求的是其最大值。
状态计算:题目提到,每次放入原料之前,可以取出不超过 \(s\) 个原料,当前有 \(j-1\),那么我们枚举取出的若干原料前已有的原料个数 \(k\),明显 \(j-1≤k≤j+s-1\),可以取走 \(0-s\) 个,但一定要放入一个。那么 \(f[i][j]=max(f[i-1][k])+a[i]*j\)。这样的时间复杂度为 \(O(nws)\),会超时,但是我们发现了 \(max(f[i-1][k])\),求一个区间的最大值,并且这个区间是已知的,我们可以使用单调队列优化。

C++代码

#include <bits/stdc++.h>
using namespace std;
const int N = 5010, M = 20010;
typedef pair<int, int> PII;
typedef long long LL;

int n, w, s;
LL a[N], f[N][N], pos[N], q[N]; // 选择前i个原料中的某些放入且总数为j的耐久度集合

int main ()
{
	scanf("%d%d%d", &n, &w, &s);
	for(int i = 1; i <= n; i ++)
		scanf("%lld", &a[i]);
	memset(f, 0x80, sizeof f);
	f[0][0] = 0;
	for(int i = 1; i <= n; i ++)
	{
		int hh = 0, tt = -1;
		q[++ tt] = f[i - 1][w];
		pos[hh] = w;
		for(int j = w; j; j --)
		{
			// for(int k = j - 1; k <= min(w, j + s - 1); k ++)
			// 	 f[i][j] = max(f[i][j], f[i - 1][k] + a[i] * j);
			while(hh <= tt && j + s - 1 < pos[hh]) hh ++;
			while(hh <= tt && q[tt] < f[i - 1][j - 1]) tt --;
			pos[++ tt] = j - 1;
			q[tt] = f[i - 1][j - 1];
			f[i][j] = q[hh] + j * a[i];
		}
	}
	LL ans = 0x8080808080808080;
	for(int j = 1; j <= w; j ++)
		ans = max(ans, f[n][j]);
	printf("%lld\n", ans);
    return 0;
}

标签:24,原料,练习,样例,times,leq,Subtask,耐久度,2022.12
From: https://www.cnblogs.com/Cocoicobird/p/17002801.html

相关文章