求助,实在找不出问题了...
查看原帖
求助,实在找不出问题了...
67476
kasugano_sora楼主2021/11/17 18:09

代码整体思路是用单调队列优化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]值大,应该对结果完全没影响才对啊......

2021/11/17 18:09
加载中...