【USACO】滑雪课程

时间:2021-12-12 18:50:26

滑雪课程
贝西去科罗拉多州去滑雪,不过还她不太会玩,只是个能力为 1 的渣渣。贝西从 0 时刻进入滑雪场,一到 T 时刻就必须离开。滑雪场里有 N 条斜坡,第 i 条斜坡滑行一次需要 Di 分钟,要求游客的能力达到 Ci 或以上时才能进入。贝西决心参加一些滑雪课程以提高自己的素质,这样可以在有限的时间内多滑几次坡。
滑雪场提供了 S 门课程。第 i 门课的开始时刻为 Mi,持续 Li 分钟,如果想参加课程,就不能迟到或早退。上完课之后,贝西的滑雪能力将变成 Ai。注意,不是能力增加 Ai,而是变成 Ai,所以乱上课的话反而会使能力下降。贝西可以随意安排她的时间:滑雪、上课,或美美地喝上一杯可可汁。请问她如何安排上课和滑雪的时间,滑坡的次数才能达到最大?
输入格式
• 第一行:三个整数 T,S 和 N,1 ≤ T ≤ 104; 1 ≤ S ≤ 100; 1 ≤ N ≤ 105
• 第二行到 S +1 行:第 i+1 行描述了第 i 门课程,分别为 Mi,Li 和 Ai,1 ≤ Mi;Li ≤ 104; 1 ≤Ai ≤ 100
• 第 S + 2 行到 S + N + 1 行:第 S + i + 1 行描述了第 i 条斜坡,分别为 Ci 和 Di,1 ≤ Ci ≤100; 1 ≤ Di ≤ 104
输出格式
• 单个整数,表示贝西可以滑完的最大次数
样例输入
10 1 2
3 2 5
4 1
1 3
样例输出
6
解释
先滑 1 次二号斜坡,然后去上课,再去一号斜坡连滑 5 次

首先我们预处理出对于每一个能力值可以滑的坡中所耗时间最少的(这样可以保证滑最多次数),用DP[i][j]表示当前在i时刻,能力值为j,

然后对于每一个状态我们可以做以下三个转移

1.什么都不做

DP[i][j]->DP[i+1][j]

2.上课(需要当前时间点有课可以上)

DP[i][j]->DP[i+该堂课的持续时间][该堂课对应的能力值]

3.滑雪

DP[i][j]->DP[i+当前能力值能滑的坡之中所耗时间最少的][j]

最后求最大次数即可。

题外话……这题的数据

超级弱,超级弱,真的,超级弱。我算法写错了能过9组……

 #include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <cmath>
using namespace std;
ifstream fin("ski.in");
ofstream fout("ski.out");
int least[]={},DP[][]={};
int lesson[][]={},po[][]={};
int tims[]={};
int ks=,ps=,xz=;
int sear(int tim,int ene);
int main(void)
{
fin>>xz>>ks>>ps;
int a=,b=,c=,most=;
memset(DP,0xff,sizeof(DP));
memset(least,0x7f,sizeof(least));
for(int i=;i<=ks;i++)
{
fin>>a>>b>>c;
lesson[i][]=a;
lesson[i][]=b;
lesson[i][]=c;
tims[a]=i;
most=max(c,most);
}
for(int i=;i<=ps;i++)
{
fin>>a>>b;
po[i][]=a;
po[i][]=b;
least[a]=min(least[a],b);
}
c=0x7fffffff;
for(int i=;i<=most;i++)
{
least[i]=min(least[i],c);
if(least[i]<c)c=least[i];
}
int ans=;
ans=sear(,);
fout<<ans;
return ;
} int sear(int tim,int ene)
{
if(tim>xz)return ;
if(DP[tim][ene]!=-)return DP[tim][ene];
int tot=,ans=;
tot=sear(tim+,ene);
ans=max(tot,ans);
if(tims[tim]!=)tot=sear(tim+lesson[tims[tim]][],lesson[tims[tim]][]);
ans=max(tot,ans);
if(tim+least[ene]<=xz)tot=sear(tim+least[ene],ene)+;
ans=max(tot,ans);
DP[tim][ene]=ans;
return ans;
}