代码整体思路是用单调队列优化dp, dp中i代表此时考虑的材料,j代表加上此时考虑的材料锅里一共有的材料总和。
dp[i][j]=max(dp[i-1][k])+a[i]*j,
k范围是(j-1,min(j-1+s,m))
下面我的代码里循环j代表在单调队列里区间的最后一位
我的代码里j是从前往后顺序考虑的,我看题解了知道逆序更简单,希望能有大佬帮忙找找我的代码问题在哪里,实在想不明白了...
下面贴一下代码,交上去是第四大点全wa,第八大点wa四个
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
const ll maxn=1e20;
ll n,w,s,ans,a[10001],dp[6001][6001],head,tail,q[10001],num[10001];
int main()
{
ans=-1e20;
cin>>n>>w>>s;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
}
for(ll i=1;i<=n;i++)
for(ll j=1;j<=s+w;j++)
{
dp[i][j]=-maxn;
}
dp[1][1]=a[1];
for(ll i=2;i<=n;i++)
{
head=1;tail=0;
memset(q,0,sizeof(q));
memset(num,0,sizeof(num));
for(ll j=1;j<=min(i+s-1,w+s-1);j++)
{
while(num[head]<j-s and head<=tail) head++;
while(dp[i-1][j]>=q[tail] and head<=tail) tail--;
if(j<=min(i-1,w))
{
q[++tail]=dp[i-1][j];
num[tail]=j;
}
if(j>=s)
{
dp[i][j-s+1]=q[head]+a[i]*(j-s+1);
}
}
}
// for(int i=1;i<=n;i++)
// for(int j=1;j<=w;j++)
// {
// cout<<dp[i][j]<<" ";
// if(j==w) cout<<endl;
// }
for(ll i=1;i<=w;i++)
{
ans=max(ans,dp[n][i]);
}
cout<<ans;
}
还有一个很神奇的地方我也没想明白,下面这句语句
if(j<=min(i-1,w))
这句语句如果不加的话第五大点也会全挂wa,但按我的理解即使之后j超过w的dp[i-1][j]入队,因为初始化过非常小,它永远不可能比在队列前面的j<=w的dp[i][j]值大,应该对结果完全没影响才对啊......