题目地址
设
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=j−1k≤min(j+s−1,w){
d
p
[
i
−
1
]
[
k
]
dp[i-1][k]
dp[i−1][k]}+
a
[
i
]
×
j
a[i]\times j
a[i]×j
k
=
j
−
1
k=j-1
k=j−1时即为不拿出来任何一个物品,
k
=
j
+
s
−
1
k=j+s-1
k=j+s−1时表示拿出
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=j−1k≤min(j+s−1){
d
p
[
i
−
1
]
[
k
]
dp[i-1][k]
dp[i−1][k]}这个式子珂以用单调队列优化啊!
相当于移动区间,求每个
[
j
−
1
,
m
i
n
(
j
+
s
−
1
)
]
[j-1,min(j+s-1)]
[j−1,min(j+s−1)]区间中的最大值。 珂以通过
O
(
w
)
O(w)
O(w)计算出
d
p
[
i
]
[
1
−
j
]
dp[i][1-j]
dp[i][1−j]的所有值。
时间复杂度
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;
}