【Codeforces】Codeforces Round #486 (Div. 3) F. Rain and Umbrellas | 动态规划

46 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【Codeforces】Codeforces Round #486 (Div. 3) F. Rain and Umbrellas | 动态规划

题目链接

Problem - F - Codeforces

题目

image.png

题目大意

Polycarp 住在数轴的 x=0x=0 点,他去找住在 x=ax=a 点的朋友。他只能从左向右移动,每秒可以通过一个单位的长度。有 nn 个关于下雨路段的描述,第 ii 个描述 li,ril_i,r_i 表示从数轴的 lil_i 点到 rir_i 点的线段上在下雨。所有关于下雨路段的描述不相交。在 Polycarp 去找住在 x=ax=a 点的朋友的路上有 mm 把伞,第 ii 把伞位于点 xix_i 并且具有重量 pip_i。最初 Polycarp 没拿着伞。

在途中的任一个点上,Polycarp 可以捡起或扔掉雨伞。Polycarp 可以携带任何数量的雨伞。因为Polycarp 不想淋湿,所以当他从 xx 移动到 x+1x+1 时,如果 [x,x+1] 在雨中,他必须拿着伞。他可以不带雨伞到一个开始下雨的地方,在这个地方拿起一把雨伞,带着雨伞前进。

Polycarp 最初的疲劳度是 0,他每拿着重量为 ww 的雨伞前进 1 个单位长度,他的疲劳度增加 ww

如果 Polycarp 可以在不淋雨的前提下到达他朋友家,最小化 Polycarp 的疲劳度。否则输出 -1。

思路

dp[i]dp[i] 表示 Polycarp 从点 ii 在不淋雨的前提下到达他朋友家的最小疲劳度。则:

  • 如过当前位置没有伞,当前位置有雨,无法到达,dp[i]=1dp[i]=-1
  • 如过当前位置没有伞,当前位置无雨,可以空手走到下一个位置,dp[i]=dp[i+1]dp[i]=dp[i+1]
  • 如过当前位置有伞,当前位置无雨,Polycarp 可以不拿这把伞空手走到下一个位置,dp[i]=dp[i+1]dp[i]=dp[i+1]
  • 如过当前位置有伞,Polycarp 拿这把伞,枚举能到达朋友家的点 jj ,假设在该位置上丢弃伞,dp[i]=min{dp[j]+umb[i](ji)}dp[i]=min\{dp[j]+umb[i]*(j-i)\}

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <map>
#include <vector>
#include <queue>
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
using LL=long long;
const int N=2001;
int n,m,len,p;
LL umb[N],dp[N],wgt;
int rain[N];
int main()
{
	scanf("%d%d%d",&len,&n,&m);
	for (int i=1,x,y;i<=n;++i)
	{
		scanf("%d%d",&x,&y);
		rain[x]++;
		rain[y]--;
	}
	for (int i=1;i<=m;++i)
	{
		scanf("%d%lld",&p,&wgt);
		if (!umb[p]) umb[p]=wgt;
		else umb[p]=min(umb[p],wgt);
	}
	for (int i=1;i<=len;++i) rain[i]+=rain[i-1];
	dp[len]=0;
	for (int i=len-1;i>=0;--i)
	{
		if (!umb[i])
		{
			if (rain[i]) dp[i]=-1;
			else dp[i]=dp[i+1];
		}
		else
		{
			if (!rain[i]) dp[i]=dp[i+1];
			else dp[i]=-1;
			for (int j=i+1;j<=len;j++)
				if (-1!=dp[j]) dp[i]=min(dp[i]==-1?dp[j]+umb[i]*(j-i):dp[i],dp[j]+umb[i]*(j-i));
		}
	}
	printf("%lld\n",dp[0]);
	return 0;
}