题目大意:
有三个整数a,n,m,a是终点坐标,给出n个范围(l,r)表示这块区域下雨,m把伞(p,w)在点p有重量为w的伞。
小明可以携带任意数量的伞,经过下雨处时必须要撑伞,小明每走一个单位长度消耗的体力与他所携带伞的重量相同,
求小明从0~a所需消耗的最少体力,若无解则输出-1。
思路:可以考虑 从 1 到 a一步步转移过去的 o(n)做法,但是写起来比较麻烦,需要保存三种状态,没有伞,和拿着伞过一段路扔掉后来又换伞的情况,以及一直都拿最轻的伞不扔的情况。
又由于 n,a 很小 考虑 o(n*n)的做法,dp[i][j] i表示当前坐标,j表示拿着第几把伞,j=0表示没有伞,然后分下雨和不下雨,当前位置有伞以及一直拿着一把伞的情况转移就好,而且 这里的坐标是一个点,而不是 一段,那么考虑 dis[l]++,dis[r]--,滚动可判断有没有雨
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define fi first
#define se second
#define pii pair<int,int>
#define inf 0x3f3f3f3f
int dis[100010],v[2010][2010], w[2010];
int pos[2010],umber[2010];
int main()
{
int a, n, m;
cin >> a >> n >> m;
a++;
for(int i = 0; i < n; i++)
{
int l,r;
cin >> l >> r;
l++; r++;
dis[l]++;
dis[r]--;
}
memset(w,inf,sizeof(w));
memset(umber, 0, sizeof(umber));
for(int i = 1; i <= m; i++)
{
int x, p;
cin >> x >> p;
x++;
pos[i] = x;
w[i] = p;
if(p < w[umber[x]])
umber[x] = i;
}
memset(v, inf, sizeof(v));
v[0][0] = 0;
int sum = 0;
for(int i = 1; i <= a; i++)
{
sum += dis[i];
for(int j = 0; j <= m; j++)
{
if(pos[j] > i) continue;
if(j) v[i][j] = min(v[i][j], v[i - 1][j] + w[j]);
if(!sum) v[i][0] = min(v[i][0], v[i - 1][j]);
if(umber[i]) v[i][umber[i]] = min(v[i][umber[i]], v[i - 1][j]+ w[umber[i]]) ;
}
}
int ans = inf;
for(int i = 0; i <= m; i++)
ans = min(ans, v[a][i]);
if(ans == inf) puts("-1");
else printf("%d\n",ans );
}