首页 > 其他分享 >【做题笔记】洛谷 P7987 [USACO21DEC] Paired Up G

【做题笔记】洛谷 P7987 [USACO21DEC] Paired Up G

时间:2023-04-28 13:45:16浏览次数:47  
标签:le 洛谷 P7987 min max sum Up 匹配 dp

在我的个人博客获得更好的阅读体验

Problem

洛谷 P7987 [USACO21DEC] Paired Up G

题目大意:

有 \(n\) 个点,其中第 \(i\) 个点位置为 \(x_i\),权值为 \(y_i\)。若两个点 \(i, j\) 满足 \(|x_i - x_j| \le k\),则这两个点之间有一条边。
求一个匹配,在满足其为极大匹配的情况下匹配点的权值和最大/最小。
求总权值和与匹配点的权值和的差。

Solution

提供一种不同于洛谷题解区的解法。

结论:作为答案的匹配中的任意两对匹配 \((a, b)\) 和 \((c, d)\),区间 \([a, b]\) 与区间 \([c, d]\) 一定不交。

这个可以用调整法证明。如果两个匹配 \((a, b)\) 和 \((c, d)\) 满足 \(a < c < b < d\),则可以将匹配调整成 \((a, c)\) 和 \((b, d)\)。
如果两个匹配 \((a, b)\) 和 \((c, d)\) 满足 \(a < c < d < b\),则匹配可以调整成 \((a, c)\) 和\((d, b)\)。

于是我们可以得到另一个结论:一个点只会与其前两个点或后两个点匹配。
因为如果某个点 \(i\) 与 \(i - 3\) 匹配,则 \(i - 2\) 和 \(i - 1\) 必然会成为匹配点。此时不满足区间无交。

于是我们就可以 \(\verb|dp|\) 了:设 \(dp_{i, 0 / 1 / 2}\) 表示只考虑前 \(i\) 个点,第 \(i\) 个点不在匹配中或与 \(i - 1\) 匹配或与 \(i - 2\) 匹配时的答案。

考虑转移。
我们不妨设 \(l_i\) 为第一个与 \(i\) 有边的节点。显然 \(1 \sim i - 1\) 中有且仅有 \(l_i \sim i - 1\) 与 \(i\) 有边。
\(l_i\) 可以双指针求出。

对于 \(dp_{i, 0}\):

  • 若 \(x_i - x_{i - 1} > k\),则 \(i - 1\) 无论是什么状态都是合法的。
  • 否则,必须满足 \(1 \sim i - 1\) 中所有与 \(i\) 有边的点都必须是匹配点。
    • 如果这些点的个数为偶数,因为每个点只能与前后四个匹配,且区间无交,且每个点都要是匹配点,所以只能相邻两个匹配。
    • 如果这些点的个数为奇数,依然相邻两个匹配,且最前面那个要与另外的点匹配。

所以有:

\[dp_{i, 0} = \left\{ \begin{array}{ll} \min/\max(dp_{i - 1, 0}, dp_{i - 1, 1}, dp_{i - 1, 2}) & x_i - x_{i - 1} > k \\ \min/\max(dp_{l_i - 1, 0}, dp_{l_i - 1, 1}, dp_{l_i - 1, 2}) + \sum\limits_{j = l_i}^{i - 1} y_j & x_i - x_{i - 1} \le k, i - l_i \equiv 0 \pmod{2} \\ \min/\max(dp_{l_i, 1}, dp_{l_i, 2}) + \sum\limits_{j = l_i + 1}^{i - 1} y_j & x_i - x_{i - 1} \le k, i - l_i \equiv 1 \pmod{2} \end{array} \right. \]

对于 \(dp_{i, 1}\),当且仅当 \(x_i - x_{i - 1} \le k\) 时才能转移,且 \(i - 2\) 无论时什么状态都是合法的。
所以有:

\[dp_{i, 1} = \left. \begin{array}{ll} \min/\max(dp_{i - 2, 0}, dp_{i - 2, 1}, dp_{i - 2, 2}) + y_{i - 1} + y_i & x_i - x_{i - 1} \le k \end{array} \right. \]

对于 \(dp_{i, 2}\):首先必须满足 \(x_i - x_{i - 2} \le k\)。
然后需要满足 \(i - 1\) 无法匹配,这里的分析与 \(dp_{i, 0}\) 类似,不再赘述。

\[dp_{i, 2} = \left\{ \begin{array}{ll} \min/\max(dp_{i - 3, 0}, dp_{i - 3, 1}, dp_{i - 3, 2}) & x_i - x_{i - 2} \le k, x_{i - 1} - x_{i - 3} > k \\ \min/\max(dp_{l_{i - 1} - 1, 0}, dp_{l_{i - 1} - 1, 1}, dp_{l_{i - 1} - 1, 2}) + \sum\limits_{j = l_{i - 1}}^{i - 2} y_j + y_i & x_i - x_{i - 2} \le k, x_{i - 1} - x_{i - 3} \le k, i - 2 - l_{i - 1} \equiv 0 \pmod{2} \\ \min/\max(dp_{l_{i - 1}, 1}, dp_{l_{i - 1}, 2}) + \sum\limits_{j = l_{i - 1} + 1}^{i - 2} y_j + y_i & x_i - x_{i - 2} \le k, x_{i - 1} - x_{i - 3} \le k, i - 2 - l_{i - 1} \equiv 0 \pmod{2} \end{array} \right. \]

然后这题就做完了。

Code

// Think twice, code once.
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

int t, n, k, x[100005], y[100005], l[100005];
long long sum[100005], dp[100005][3];

int main() {
	scanf("%d%d%d", &t, &n, &k);
	for (int i = 1; i <= n; i++) scanf("%d%d", &x[i], &y[i]), sum[i] = sum[i - 1] + y[i];
	for (int ri = 1, le = 1; ri <= n; ri++) {
		while (x[ri] - x[le] > k) le++;
		l[ri] = le;
	}
	if (t == 1) {
		long long inf = ~0x3f3f3f3f3f3f3f3f;
		memset(dp, ~0x3f, sizeof(dp));
		dp[0][0] = 0;
		dp[1][0] = 0;
		if (x[2] - x[1] > k) dp[2][0] = 0;
		else dp[2][1] = y[1] + y[2];
		if (x[3] - x[2] > k) dp[3][0] = max(dp[2][0], dp[2][1]);
		else {
			dp[3][0] = dp[2][1];
			dp[3][1] = y[2] + y[3];
			if (x[3] - x[1] <= k) dp[3][2] = y[1] + y[3];
		}
		for (int i = 4; i <= n; i++) {
			if (x[i] - x[i - 1] > k)
				dp[i][0] = max({dp[i - 1][0], dp[i - 1][1], dp[i - 1][2]});
			else if ((i - l[i]) % 2 == 0)
				dp[i][0] = max({dp[l[i] - 1][0], dp[l[i] - 1][1], dp[l[i] - 1][2]}) +
					sum[i - 1] - sum[l[i] - 1];
			else dp[i][0] = max(dp[l[i]][1], dp[l[i]][2]) + sum[i - 1] - sum[l[i]];
			if (x[i] - x[i - 1] <= k)
				dp[i][1] = max({dp[i - 2][0], dp[i - 2][1], dp[i - 2][2]}) + y[i - 1] + y[i];
			if (x[i] - x[i - 2] <= k) {
				if (x[i - 1] - x[i - 3] > k)
					dp[i][2] = max({dp[i - 3][0], dp[i - 3][1], dp[i - 3][2]}) + y[i - 2] + y[i];
				else if ((i - 2 - l[i - 1]) % 2 == 0)
					dp[i][2] =
						max({dp[l[i - 1] - 1][0], dp[l[i - 1] - 1][1], dp[l[i - 1] - 1][2]}) +
						sum[i - 2] - sum[l[i - 1] - 1] + y[i];
				else dp[i][2] = max(dp[l[i - 1]][1], dp[l[i - 1]][2]) +
						sum[i - 2] - sum[l[i - 1]] + y[i];
			}
			if (dp[i][0] < 0) dp[i][0] = inf;
			if (dp[i][1] < 0) dp[i][1] = inf;
			if (dp[i][2] < 0) dp[i][2] = inf;
		}
		printf("%lld\n", sum[n] - max({dp[n][0], dp[n][1], dp[n][2]}));
	} else {
		long long inf = 0x3f3f3f3f3f3f3f3f;
		memset(dp, 0x3f, sizeof(dp));
		dp[0][0] = 0;
		dp[1][0] = 0;
		if (x[2] - x[1] > k) dp[2][0] = 0;
		else dp[2][1] = y[1] + y[2];
		if (x[3] - x[2] > k) dp[3][0] = min(dp[2][0], dp[2][1]);
		else {
			dp[3][0] = dp[2][1];
			dp[3][1] = y[2] + y[3];
			if (x[3] - x[1] <= k) dp[3][2] = y[1] + y[3];
		}
		for (int i = 4; i <= n; i++) {
			if (x[i] - x[i - 1] > k)
				dp[i][0] = min({dp[i - 1][0], dp[i - 1][1], dp[i - 1][2]});
			else if ((i - l[i]) % 2 == 0)
				dp[i][0] = min({dp[l[i] - 1][0], dp[l[i] - 1][1], dp[l[i] - 1][2]}) +
					sum[i - 1] - sum[l[i] - 1];
			else dp[i][0] = min(dp[l[i]][1], dp[l[i]][2]) + sum[i - 1] - sum[l[i]];
			if (x[i] - x[i - 1] <= k)
				dp[i][1] = min({dp[i - 2][0], dp[i - 2][1], dp[i - 2][2]}) + y[i - 1] + y[i];
			if (x[i] - x[i - 2] <= k) {
				if (x[i - 1] - x[i - 3] > k)
					dp[i][2] = min({dp[i - 3][0], dp[i - 3][1], dp[i - 3][2]}) + y[i - 2] + y[i];
				else if ((i - 2 - l[i - 1]) % 2 == 0)
					dp[i][2] =
						min({dp[l[i - 1] - 1][0], dp[l[i - 1] - 1][1], dp[l[i - 1] - 1][2]}) +
						sum[i - 2] - sum[l[i - 1] - 1] + y[i];
				else dp[i][2] = min(dp[l[i - 1]][1], dp[l[i - 1]][2]) +
						sum[i - 2] - sum[l[i - 1]] + y[i];
			}
			if (dp[i][0] > inf) dp[i][0] = inf;
			if (dp[i][1] > inf) dp[i][1] = inf;
			if (dp[i][2] > inf) dp[i][2] = inf;
		}
		printf("%lld\n", sum[n] - min({dp[n][0], dp[n][1], dp[n][2]}));
	}
	return 0;
}

标签:le,洛谷,P7987,min,max,sum,Up,匹配,dp
From: https://www.cnblogs.com/mk-oi/p/LuoguP7987.html

相关文章

  • Vulkan Support Check and Dynamic Loader C++ code sample
    很多时候不想静态依赖VulkanSDK所提供的静态库,因为会遇到一些过早的电脑不支持vulkan,那么就需要使用动态加载vulkan-1.dll(forWindows)或libMoltenVK.dylib(forMacOS)的方式进行判断了。VulkanSDK提供了相关头文件实现可以做到相关功能,仅需要include一下头文件`vulkan/vulkan.hpp......
  • The principle of uploading files with command line tools All In One
    TheprincipleofuploadingfileswithcommandlinetoolsAllInOne命令行工具文件上传的原理/TheprincipleofcommandlinetoolfileuploaddemospipgitCDNOSS{"name":"xui","version":"1.0.0","main&q......
  • linux下利用nohup后台运行jar文件包程序
    Linux运行jar包命令如下:方式一: 1.java-jarXXX.jar特点:当前ssh窗口被锁定,可按CTRL+C打断程序运行,或直接关闭窗口,程序退出那如何让窗口不锁定?方式二 1.java-jarXXX.jar&&代表在后台运行。特定:当前ssh窗口不被锁定,但是当窗口关闭时,程序中止运行。继续改......
  • 数据库还原失败System.Data.SqlClient.SqlError: 无法执行 BACKUP LOG,因为当前没有数
    https://www.shuzhiduo.com/A/1O5EbK6yd7/高版本可以兼容低版本的数据库哎。所以低版本可以直接还原到高版本。过程中提示数据库还原失败System.Data.SqlClient.SqlError:无法执行BACKUPLOG,因为当前没有数据库备份,按照链接中的第二个方法解决了: 在还原的界面中,取消勾选还......
  • BigDecimal的setScale常用方法(ROUND_UP、ROUND_DOWN、ROUND_HALF_UP、ROUND_HALF_DOW
    BigDecimal的setScale四大常用方法总结//设置小数点后第三位数字一大一小观察效果BigDecimalnum=newBigDecimal("3.3235667");BigDecimalnumOne=newBigDecimal("3.3275667");1、ROUND_UP:进位制:不管保留数字后面是大是小(0除外)都会进1//ROUND_UP--进位制:不管保留数......
  • Python3+cgroupspy安装使用教程
    一、系统资源使用限制的必要性探讨对于一个脚本,最基础的限制是要限制单进程实例以保证了不会存在多个进程实例、在运行程序主体逻辑前检测系统资源剩余量确保自己不是压夸系统的最后一根稻草、设置程序运行超时时间以保证进程实例不会无休止地运行下去。进一步,在部署有可用性要......
  • Mac M1(arm 系列芯片)如何安装 Chromium | Puppeteer
    最近写个脚本用到puppeteer,然后安装Chromium出现一点问题,这里记录一下解决方案。Puppeteer自动安装失败在Puppeteer安装时会自动安装Chromium,然而却总是报错502导致下载失败,直接下载可以下载,命令行wget也可以,猜测是因为Puppeteer开启了新的process来安装导致环境......
  • upupw mysql数据库密码初始化
    1、启动upupw2、打开cmd窗口,进入到数据库目录/UPUPW/MariaDB/bin。3、执行命令:mysql -uroot-p;4、用系统提供的密码登录,默认的是:DRsXT5ZJ6Oi55LPQ5、进入mysql管理界面后,执行命令:updateusersetauthentication_string=password("root")whereuser='root'; 提示:Query......
  • 深度了解group分组查询
    使用groupby的简单例子groupby工作原理groupby+where和groupby+having的区别groupby优化思路groupby使用注意点一个生产慢SQL如何优化1.使用groupby的简单例子groupby一般用于分组统计,它表达的逻辑就是根据一定的规则,进行分组。我们先从一个简单的例子......
  • JS 数组 group by 分组
    扩展数组方法Array.prototype.groupBy=functiongroupBy(key){  consthash={},    result=[];  for(constelofthis){    if(hash[el[key]]){      hash[el[key]].push(el);    }else{      r......