首页 > 其他分享 >题解:洛谷P2339 [USACO04OPEN] Turning in Homework G

题解:洛谷P2339 [USACO04OPEN] Turning in Homework G

时间:2024-10-03 18:50:56浏览次数:8  
标签:Turning int 题解 作业 区间 Homework USACO04OPEN dp dis

题目链接:洛谷P2339 [USACO04OPEN] Turning in Homework G

首先我们考虑如何处理到达给定时间后才能交作业这一限制。其实在生活中,我们一般只会考虑什么时候交作业截止 (除了某些卷王),这样我们只用考虑如何在最大结束时间之前交作业,而不是在所有作业都没开始交之前考虑如何转悠(前者明显比后者简单),这样我们可以先二分答案贝茜交齐所有作业的总时间,再来判断能否在这时间内从原来的终点交齐作业并最终来到原来的起点。

现在考虑如何判断是否可以在给定条件下交齐所有作业。可以知道如果有三份要交的作业 \(A, B, C\),他们距离当前点的距离 \(x_A < x_B < x_C\),由图:

可得从起始点先到 \(A\) 再到 \(B\) 最后到 \(C\) 一定优于从 先从起点到 \(B\) 再到 \(A\) 最后到 \(C\),因此,如果贝茜要在这条走廊上来回交作业,那么她每次改变方向后所走的区间长度总小于上一次,而不是先走一个大区间,再走一个小区间,然后又走一个大区间。反过来,这就是一个从小区间推到大区间的过程,可以用区间 DP 做了。

考虑设 \(dp_{l, r, 0/1}\) 表示交完 \(l\) 到 \(r\) 区间内的作业,最后停留在左端点 \(l\) 的最小时间为 \(dp_{l, r, 0}\),停留在右端点 \(r\) 的最小时间为 \(dp_{l, r, 1}\),下面分四种情况讨论:

  • 现在在某个区间的左端点,要往左继续交作业。

  • 现在在某个区间的右端点,要往左继续交作业。

  • 现在在某个区间的左端点,要往右继续交作业。

  • 现在在某个区间的右端点,要往右继续交作业。

每种情况只用考虑到达时交作业是否截止,如果没有截止就可以更新答案,因此 DP 方程为:

\[dp_{l, r, 0} = \begin{cases} dp_{l + 1, r, 0} + dis_{l + 1} - dis_l & & dp_{l + 1, r, 0} + dis_{l + 1} - dis_l \leq time_l\\ dp_{l + 1, r, 1} + dis_r - dis_l & & dp_{l + 1, r, 1} + dis_r - dis_l \leq time_l \end{cases} \]

\[dp_{l, r, 1} = \begin{cases} dp_{l, r - 1, 1} + dis_r - dis_{r - 1} & & dp_{l, r - 1, 1} + dis_r - dis_{r - 1} \leq time_r\\ dp_{l, r - 1, 0} + dis_r - dis_l & & dp_{l, r - 1, 0} + dis_r - dis_l \leq time_r \end{cases} \]

注意:

  1. 将时间倒序后,记得将交作业截止时间更新为总时间减去原先开始交作业的时间。

  2. 记得将出发点与结束点也存为一个办公室,方便统计答案。

完整代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 9;
struct Homework{
	int x, t;
} h[N];
bool cmp(Homework a, Homework b){
	if(a.x == b.x)
		return a.t < b.t;
	return a.x < b.x;
}
int C, H, B;
int tmp[N];
int dp[N][N][2];
bool chk(int tim){
	for(int i = 1; i <= C; i++){
		tmp[i] = tim - h[i].t;
		if(h[i].t > tim)
			return 0;
	}
	memset(dp, 0x3f, sizeof(dp));
	dp[B][B][0] = dp[B][B][1] = 0;
	for(int len = 2; len <= C; len++)
		for(int l = 1; l + len - 1 <= C; l++){
			int r = l + len - 1;
			if(dp[l + 1][r][0] + h[l + 1].x - h[l].x <= tmp[l])
				dp[l][r][0] = min(dp[l][r][0], dp[l + 1][r][0] + h[l + 1].x - h[l].x);
			if(dp[l + 1][r][1] + h[r].x - h[l].x <= tmp[l])
				dp[l][r][0] = min(dp[l][r][0], dp[l + 1][r][1] + h[r].x - h[l].x);
			if(dp[l][r - 1][1] + h[r].x - h[r - 1].x <= tmp[r])
				dp[l][r][1] = min(dp[l][r][1], dp[l][r - 1][1] + h[r].x - h[r - 1].x);
			if(dp[l][r - 1][0] + h[r].x - h[l].x <= tmp[r])
				dp[l][r][1] = min(dp[l][r][1], dp[l][r - 1][0] + h[r].x - h[l].x);
		}
	if(dp[1][C][0] != 0x3f3f3f3f)
		return 1;
	else
		return 0;
}
int main(){
	scanf("%d%d%d", &C, &H, &B);
	for(int i = 1; i <= C; i++)
		scanf("%d%d", &h[i].x, &h[i].t);
	h[++C] = Homework{B, 0};
	++C;
	sort(h + 1, h + C + 1, cmp);
	for(int i = 1; i <= C; i++)
		if(h[i].x == B && h[i].t == 0){
			B = i;
			break;
		}
	int l = 1, r = N * N;
	while(l <= r){
		int mid = (l + r) >> 1;
		if(chk(mid))
			r = mid - 1;
		else
			l = mid + 1;
	}
	printf("%d", r + 1);
	return 0;
}

标签:Turning,int,题解,作业,区间,Homework,USACO04OPEN,dp,dis
From: https://www.cnblogs.com/JPGOJCZX/p/18445881

相关文章

  • 题解:CF2009G1 Yunli's Subarray Queries (easy version)
    题目要求\(a_i=a_{i-1}+1\),设\(b_i=a_i-i\),如果\(b_i=b_j\),那么\(i\)和\(j\)就在正确的相对位置上。这应该很好理解吧,\(a\)是一个公差为\(1\)的等差数列,下标也是一个公差为\(1\)的等差数列,对应位置相减就相等了。我们在输入\(a_i\)的时候减去\(i\),然后用滑动窗口......
  • [题解] [SDOI2011] 消防
    [题解][SDOI2011]消防tag:图论、树、树的直径题目链接(洛谷):https://www.luogu.com.cn/problem/P2491题目描述给定一棵\(n\)个节点的树,第\(i\)条边有边权\(z_i\)。要求找到树上一条长度不大于\(s\)的简单路径,使得不在路径上的点到该路径的最大距离最小。数据范围:\(1......
  • 算法基础课——基础算法题解
    排序算法(分治)快速排序:题面:给定你一个长度为\(n\)的整数数列。请你使用快速排序对这个数列按照从小到大进行排序。并将排好序的数列按顺序输出。输入格式输入共两行,第一行包含整数\(n\)。第二行包含\(n\)个整数(所有整数均在\(1\sim10^9\)范围内),表示整个数列。输......
  • 题解9.29-10.3
    1.MakeitAlternating如果它已经是交替的序列我们就不用管了,最终的目的是把序列变成交替的序列,那么我们可以把连续相同的数全部取出来只留下一个,可以分成几段相同的数,最后的结果就是把这些相同的数全部只保留一个,用排列组合C(m,1);第一个结果很简单,把重复的数加一下即可,后面的答......
  • CF1051F题解
    传送门:https://codeforces.com/problemset/problem/1051/F注意到\(m-n\le20\),求一个连通图中任意两点间最短路,我们不难想到将问题转换到树上。先求出树的任意一颗生成树,此时倍增或者树刨能轻松算出仅含树边的最小路径。而对于非树边,从边的角度显然很难做到,我们不妨从点的角度思......
  • 题解:CF724E Goods transportation
    可以在cnblog中阅读。题意有\(n\)座城市,第\(i\)座城市生产了\(p_i\)件货物,最多可以出售\(s_i\)件货物,编号小的城市可以向编号大的城市运输至多\(c\)件货物,问最多能出售多少货物。\(n\le10^4\)。分析乍一看是一个网络流问题,可以这样建图,令\(S\)为源点\(T\)......
  • ABC221G Jumping Sequences 题解
    JumpingSequences把移动的上下左右改成左上、左下、右上、右下(坐标轴旋转\(45\)°)。则最终目的地是\((A+B,A-B)\)。(以前移动的方式是\((\pmd_i,0),(0,\pmd_i)\)。现在每次移动的方式是\((\pmd_i,\pmd_i)\))则\(x,y\)两维可以分开考虑。目标:从\(d_1\simd_n\)中选......
  • Codeforces Round 976 (Div. 2) 题解
    CodeforcesRound976(Div.2)题解2020B一个常见的想法:开关灯=异或,虽然在这道题里没啥用注意到,第i盏灯的按钮被按的次数就是i的除它本身以外的因子个数而完全平方数的因子数为奇数,其他数的因子数为偶数点击查看更多信息#include<bits/stdc++.h>usingnamespacestd;voi......
  • 题解:CF1976D Invertible Bracket Sequences
    可以在cnblog中阅读。题意给一个合法括号序列,问有多少区间\([l,r]\),使得将区间内的每个括号翻转后,括号序列仍合法。分析十分套路地,我们将(看成\(+1\),将)看成\(-1\),则一个括号序列合法的充要条件是转换后的序列满足:前缀和任意位置非负;最后一项为\(0\)。考虑翻转......
  • ZZJC新生训练赛第二场题解
    先给出比赛链接:https://ac.nowcoder.com/acm/contest/92036A小红打怪ShowCodeAclassPoint{//点类public:intx,y;Point(){}Point(intx,inty):x(x),y(y){}Pointoperator+(constPoint&P)const{returnPoint(x+P.x,y+P.y);......