洛谷 P5858 「SWTR-03」Golden Sword 题解

8 篇文章 0 订阅
3 篇文章 0 订阅

题目地址

d p [ i ] [ j ] dp[i][j] dp[i][j]表示放入前 i i i个物品且锅中还有 j j j个物品所获得的最大耐久度。
很容易推出 d p [ i ] [ j ] = M a x k = j − 1 k ≤ m i n ( j + s − 1 , w ) dp[i][j]=Max_{k=j-1}^{k \le min(j+s-1,w)} dp[i][j]=Maxk=j1kmin(j+s1,w){ d p [ i − 1 ] [ k ] dp[i-1][k] dp[i1][k]}+ a [ i ] × j a[i]\times j a[i]×j
k = j − 1 k=j-1 k=j1时即为不拿出来任何一个物品, k = j + s − 1 k=j+s-1 k=j+s1时表示拿出 s s s个物品, − 1 -1 1是为了给第 i i i个物品留个位置。
如果打三重的 f o r for for语句的话,时间复杂度为 O ( n 3 ) O(n^3) O(n3),咕咕咕。
然而 M a x k = j − 1 k ≤ m i n ( j + s − 1 ) Max_{k=j-1}^{k \le min(j+s-1)} Maxk=j1kmin(j+s1){ d p [ i − 1 ] [ k ] dp[i-1][k] dp[i1][k]}这个式子珂以用单调队列优化啊!
相当于移动区间,求每个 [ j − 1 , m i n ( j + s − 1 ) ] [j-1,min(j+s-1)] [j1,min(j+s1)]区间中的最大值。 珂以通过 O ( w ) O(w) O(w)计算出 d p [ i ] [ 1 − j ] dp[i][1-j] dp[i][1j]的所有值。
时间复杂度 O ( n 2 ) O(n^2) O(n2),能过。
C o d e \color{blue}Code Code

# include <bits/stdc++.h>
using namespace std;
// const
const int N=5505;
const long long inf=103492948382342342;
//move int
int n,w,s;
long long dp[N][N];
long long a[N];
int front,rear;
struct node
{
	long long _time;
	long long x;
	//node(int _timer,long long _x){_time=_timer,x=_x;}
};
node q[N+10];
inline long long read(void) 
{
	long long s=0;
	int w=1;
	char ch=getchar() ;
	while(!isdigit(ch))
	{
		if(ch=='-') w=-1;
		ch=getchar() ;
	}
	while(isdigit(ch)) 
	{
		s=s*10+ch-'0';
		ch=getchar() ;
	}
	return s*w;
}
void Input(void) 
{
	n=read(),w=read(),s=read() ;
	for(int i=1;i<=n;i++) 
	{
		a[i]=read() ;
	}
	return;
}
void solve(void) 
{
	for(int i=0;i<=n;i++) 
	{
		for(int j=0;j<=w;j++) 
		{
			dp[i][j]=-inf;
		}
	}
	dp[0][0]=0;
	//compare
	for(int i=1;i<=n;i++) 
	{
		for(int k=1;k<=10;k++) q[k].x=q[k]._time=0;
		front=rear=0;
		q[++rear].x=dp[i-1][w];
		q[rear]._time=w; 
		for(int j=w;j>=1;j--) 
		{
			while(q[front+1]._time>j+s-1&&front<rear) 
			{
				front++;
			}
			while(q[rear].x<=dp[i-1][j-1]&&front<rear) 
			{
				rear--;
			}
			rear++;
			q[rear].x=dp[i-1][j-1];
			q[rear]._time=j-1;
			dp[i][j]=q[front+1].x+a[i]*j;
		}
	}
	long long ans=-inf;
	for(int i=0;i<=w;i++) 
	{
		ans=max(ans,dp[n][i]) ;
	}
	cout<<ans<<endl ;
}
int main(void) 
{
	Input() ;
	solve() ;
	return 0;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值