? 我已经很久很久,很久很久,没有只依靠自己想出一个DP了。开心。
? 首先设计一下状态,\(f_{i,j}\) 表示在时间 i ,能力值为 j 的时候能滑的最多场数。
? 接下来考虑在第 i 秒能干什么。有以下选项:
啥也不干,于是 \(f_{i+1,j}\) 可以被 \(f_{i,j}\) 更新
上一节课,\(f_{i+L_k,A_k}\) 可以被 \(f_{i,j}\) 更新,\(k\) 为一个在 i 时间开始的课程。
滑一场雪,\(f_{i+D_k,j}\) 可以被 \(f_{i,j}\) 更新,\(k\) 为一个滑雪场。
? 但是现在时间复杂度很显然不对,到达了 \(O(TVN)\) 的级别,其中 \(V\) 为能力值域。
? 问题在于枚举一个滑雪场过于冗杂。观察到一个滑雪场可以滑多次,这启发我们贪心,对于一切以当前能力值可以滑的场,总是从中选一个耗时最小的来滑。就可以省去枚举。
? 而这个耗时最小的场既可以用数据结构维护也可以提前预处理,此处我选择预处理,预处理时间复杂度为\(O(NV)\),总的时间复杂度在 \(O(VN+TV+VS)\), \(VS\) 是因为每堂课会被枚举V次。
? 初始化为 \(f_{0,1}=0\),其余负无穷。
#define fe(i,a,b) for(int i=a;i<=b;++i)
#define pii pair<int,int>
#define mp(a,b) make_pair(a,b)
const int inf=1e9;
int t,s,n,minn[105],f[20005][105],ans;
vector< pii > cl[10005];
inline int M_min(int a,int b){return a<b?a:b;}
inline int M_max(int a,int b){return a>b?a:b;}
int main(){
t=read(),s=read(),n=read();
fe(i,0,100)minn[i]=inf;
fe(i,1,s){
int x=read(),y=read(),z=read();
cl[x].push_back(mp(y,z));
}
fe(i,1,n){
int c=read(),d=read();
fe(j,c,100)minn[j]=M_min(minn[j],d);
}
memset(f,-0x3f,sizeof(f));
f[0][1]=0;
fe(i,0,t){
int u=cl[i].size();
fe(j,0,100)if(f[i][j]>=0){
ans=M_max(ans,f[i][j]);
fe(k,0,u-1)f[i+cl[i][k].first][cl[i][k].second]=M_max(f[i][j],f[i+cl[i][k].first][cl[i][k].second]);
f[i+1][j]=M_max(f[i+1][j],f[i][j]);
if(i+minn[j]<=t)f[i+minn[j]][j]=M_max(f[i+minn[j]][j],f[i][j]+1);
}
}
printf("%d",ans);
return 0;
}
[LuoguP2948][USACO09OPEN]Ski Lessons G
原文:https://www.cnblogs.com/clockwhite/p/14071809.html