题没什么好说的,就是滑动窗口+背包
主要讲讲怎么实现
$deque$版(这个是对的但是STL常数过大)
#include<bits/stdc++.h>
using namespace std;
int pre[100001],dp[100001];
int N,V,w,v,s;
int main(){
cin>>N>>V;
for(int i=1;i<=N;i++){
cin>>v>>w>>s;
memcpy(pre,dp,sizeof(dp));
for(int j=0;j<v;j++){
deque<int>q;
for(int k=j;k<=V;k+=v){
if(!q.empty()&&k-s*v>q.front()){
q.pop_front();
}
while(!q.empty()&&pre[q.back()]-(q.back()-j)/v*w<=pre[k]-(k-j)/v*w)q.pop_back();
if(!q.empty()){
dp[k]=max(dp[k],pre[q.front()]+(k-q.front())/v*w);
}
q.push_back(k);
}
}
}
cout<<dp[V]<<endl;
return 0;
}
用数组和双指针模拟双向队列
因为每一次tail都从-1开始,在过程中也不会考虑后面的元素,所以说不需要重置
#include<bits/stdc++.h>
using namespace std;
int pre[100001],dp[100001];
int N,V,w,v,s;
int q[100001];
int main(){
cin>>N>>V;
for(int i=1;i<=N;i++){
scanf("%d%d%d",&v,&w,&s);
memcpy(pre,dp,sizeof(dp));
for(int j=0;j<v;j++){
int head=0,tail=-1;
for(int k=j;k<=V;k+=v){
if(head<=tail&&k-s*v>q[head]){
head++;
}
while(head<=tail&&pre[q[tail]]-(q[tail]-j)/v*w<=pre[k]-(k-j)/v*w)tail--;
if(head<=tail){
dp[k]=max(dp[k],pre[q[head]]+(k-q[head])/v*w);
}
q[++tail]=k;
}
}
}
cout<<dp[V]<<endl;
return 0;
}