【USACO2009 Open】滑雪课程ski
【USACO2009 Open】滑雪课程 Ski Lessons
- Time Limit: 1000 ms
- Memory Limit: 131072 KBytes
Description
约翰请贝西去科罗拉多去滑雪。不过贝西不太会玩,她只是个滑雪能力为1的渣渣。所以她决心参加一些滑雪课程。滑雪场提供S门课程,第i门课开始的时间是Mi,持续时间为Li ,上完课之后,贝西的滑雪能力将变成Ai。注意,能力不是增加Ai,而是变成Ai。
滑雪场有N条斜坡,第i条斜坡滑行一次需要Di 分钟,要求游客的滑雪能力达到Ci或以上时才能进入。
贝西可以随意安排她的时间:滑雪、上课,或美美地喝上一杯可可汁,但她在滑雪场只能呆到第T分钟。请问她如何安排时间,滑行次数才能尽量多?
Input
第一行:三个用空格分开的整数:T,S和N,1 ≤ T ≤ 10^4,1 ≤ S ≤ 100,1 ≤ N ≤ 10^5
第二行到S + 1行:第i + 1行描述了第i门课程,分别为Mi,Li 和Ai,彼此用空格隔开,1 ≤ Mi , Li ≤ 10^4,1 ≤ Ai ≤ 100
第S + 2行到S + N + 1行:第S + i + 1行描述了第i条斜坡,分别为Ci和Di ,彼此用空格隔开,1 ≤ Ci ≤ 100,1 ≤ Di ≤ 10^4
Output
第一行:单个整数,表示在时限内贝西可以滑完的最大次数
Sample Input
10 1 2
3 2 5
4 1
1 3
Sample Output
6
Hint
先滑 1 次 2 号斜坡,然后去上课,再去 1号连滑 5 次,一共 6 次
我实在太弱...这题做了特别久
这其实是一道简单的dp,首先状态f[i][j] 表示到第i个时刻贝茜的能力值为j时能滑的最大次数
接下来,转移,这时候有三种转移方式:1、美美地给自己倒一杯卡布奇诺(不要问我哪来的卡布奇诺) 2、上课长知识 3、就剩滑冰了吧
这样我们就可以得到一个转移方程:
(1<=k<=j)最后一个转移应为f[i-tn[j]][j]+1
那么肯定有人要问l[i][j]是什么,tn[j]又是什么,其实l[i][j]就是到第i时刻上课已经结束能得到j能力值的课程开始的最晚时刻,tn[j]就是能力值为j时滑一次雪所需的最短时间(一个小贪心)
嗯~~~看起来这样就可以A掉这题了
其实
不然
如果我们枚举k,那么就会T掉,所以我们可以加一个数组g[i],在dp过程中顺便记录下每个时刻f[i][k]的最大值来优化这个方程,这样就可以完美将其解决掉了OwO
什么?没听懂?下面是代码
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 int l[10050][105],tn[105],f[10050][105],g[10050]; 6 int main() 7 { 8 int t,s,n,st,ai,ei; 9 memset(f,128,sizeof(f)); 10 memset(g,128,sizeof(g)); 11 memset(tn,127,sizeof(tn)); 12 scanf("%d%d%d",&t,&s,&n); 13 for (int i=1;i<=s;i++){ 14 scanf("%d%d%d",&st,&ai,&ei); 15 l[st+ai][ei]=max(l[st+ai][ei],st); 16 } 17 int c,d; 18 for (int i=1;i<=n;i++){ 19 scanf("%d%d",&c,&d); 20 for (int j=c;j<=100;j++) 21 tn[j]=min(tn[j],d); 22 } 23 f[0][1]=0; 24 for (int i=1;i<=t;i++) 25 for (int j=1;j<=100;j++){ 26 f[i][j]=f[i-1][j]; 27 if (l[i][j]) f[i][j]=max(f[i][j],g[l[i][j]]); 28 if (i>=tn[j]) f[i][j]=max(f[i][j],f[i-tn[j]][j]+1); 29 g[i]=max(g[i],f[i][j]); 30 } 31 printf("%d",g[t]); 32 return 0; 33 }