题解 P6040 【「ACOI2020」课后期末考试滑溜滑溜补习班】
单调队列优化DP的板子题吖,很适合萌新上手
20 分做法
假设
对于其他的
当然
对于每个
100 分做法
只需要做一点点改动就可以拿到满分了(巨大的跨越)。
由状态转移方程知,可以影响
对于一个学生
这意味着,我们对于每个
每次得到
1.弹出单调队列的过期元素(
j<i-x )
2.取出单调队列的第一个元素,得到f[i]
3.将(f[i],i) 打包放入单调队列中,并弹出
弹出的条件是什么呢?并不是简单的
附上核心代码,仅供参考
deque<pair<LL,int> >q; //不开LL见祖宗
if(x==1){ //杀老师不能跳过时,需特判
for(int i=1;i<=n;++i)f[n]+=a[i];
cout<<f[n]+k*(LL)(n-1);
return 0;
}
f[1]=a[1];
q.push_back(make_pair(f[1],1)); //预处理
for(int i=2;i<=n;++i){
while(!q.empty()){
if(q.front().second<i-x)q.pop_front();
else break; //弹出过期元素
}
LL fx=q.front().first;int lx=q.front().second;
f[i]=fx+k+d*(LL)(i-lx-1)+a[i]; //得到f[i]
while(!q.empty()){
LL fx=q.back().first;int lx=q.back().second;
if(fx+d*(LL)(i-lx)>=f[i])q.pop_back();
else break; //弹出
}
q.push_back(make_pair(f[i],i)); //压入当前元素
}
cout<<f[n];