题目链接
题意: 给一个初始纯度值
m
m
m,一共度过
n
n
n天,给出序列
a
[
i
]
a[i]
a[i]和
b
[
i
]
b[i]
b[i],第
i
i
i天可以执行下列操作方案之一:
- 不操作;
- 用 a [ i ] a[i] a[i]纯度值换取 b [ i ] b[i] b[i]金钱收益;
- 用 a [ i ] a[i] a[i]纯度值换取 2 ∗ b [ i ] 2*b[i] 2∗b[i]金钱收益,但是第 i + 1 i+1 i+1天的金钱收益 b [ i + 1 ] b[i+1] b[i+1]将降为 ⌊ b [ i + 1 ] 2 ⌋ \lfloor\frac{b[i+1]}{2}\rfloor ⌊2b[i+1]⌋,而且第 i + 1 i+1 i+1天只能选择操作 1 1 1和操作 2 2 2;
- 用 a [ i ] a[i] a[i]纯度值换取 3 ∗ b [ i ] 3*b[i] 3∗b[i]金钱收益,但是第 i + 1 i+1 i+1天的金钱收益 b [ i + 1 ] b[i+1] b[i+1]将降为 0 0 0,第 i + 2 i+2 i+2天的金钱收益 b [ i + 2 ] b[i+2] b[i+2]将降为 ⌊ b [ i + 2 ] 3 ⌋ \lfloor\frac{b[i+2]}{3}\rfloor ⌊3b[i+2]⌋,而且第 i + 2 i+2 i+2天只能选择操作 1 1 1和操作 2 2 2;
求一种方案使得获得的总金币收益最大。
数据范围: 1 ≤ n ≤ 10000 1\leq n\leq 10000 1≤n≤10000, 1 ≤ m ≤ 10000 1\leq m\leq 10000 1≤m≤10000, 1 ≤ a [ i ] ≤ 10000 1≤a[i]≤10000 1≤a[i]≤10000, 0 ≤ b [ i ] ≤ 1 0 9 0≤b[i]≤10^9 0≤b[i]≤109
思路:
因为
n
n
n和
m
m
m是
1
e
4
1e4
1e4,考虑用
O
(
n
m
)
O(nm)
O(nm)的dp来做,
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]是到第
i
i
i天,已消耗纯度值为
j
j
j的最大收益,
可以根据上面四种操作方案,可以对应写出转移方程:
1.
d
p
1.\ \ dp
1. dp
[
i
]
[i]
[i]
[
j
]
=
d
p
[j]=dp
[j]=dp
[
i
−
1
]
[i-1]
[i−1]
[
j
]
[j]
[j]
2.
d
p
2.\ \ dp
2. dp
[
i
]
[i]
[i]
[
j
]
=
d
p
[j]=dp
[j]=dp
[
i
−
1
]
[i-1]
[i−1]
[
j
−
a
[
i
]
]
+
b
[
i
]
[j-a[i]]+b[i]
[j−a[i]]+b[i]
3.
j
≥
1
3.\ \ j\geq 1
3. j≥1时,
d
p
dp
dp
[
i
]
[i]
[i]
[
j
]
=
m
a
x
(
d
p
[j]=max(dp
[j]=max(dp
[
i
−
2
]
[i-2]
[i−2]
[
j
−
a
[
i
−
1
]
]
+
2
∗
b
[
i
−
1
]
,
d
p
[j-a[i-1]]+2*b[i-1],dp
[j−a[i−1]]+2∗b[i−1],dp
[
i
−
2
]
[i-2]
[i−2]
[
j
−
a
[
i
−
1
]
−
a
[
i
]
]
+
2
∗
b
[
i
−
1
]
+
b
[
i
]
/
2
)
[j-a[i-1]-a[i]]+2*b[i-1]+b[i]/2)
[j−a[i−1]−a[i]]+2∗b[i−1]+b[i]/2)
4.
j
≥
2
4.\ \ j\geq 2
4. j≥2时,
d
p
dp
dp
[
i
]
[i]
[i]
[
j
]
=
m
a
x
(
d
p
[j]=max(dp
[j]=max(dp
[
i
−
3
]
[i-3]
[i−3]
[
j
−
a
[
i
−
2
]
]
+
3
∗
b
[
i
−
2
]
,
d
p
[j-a[i-2]]+3*b[i-2],dp
[j−a[i−2]]+3∗b[i−2],dp
[
i
−
3
]
[i-3]
[i−3]
[
j
−
a
[
i
−
2
]
−
a
[
i
]
]
+
3
∗
b
[
i
−
2
]
+
b
[
i
]
/
3
)
[j-a[i-2]-a[i]]+3*b[i-2]+b[i]/3)
[j−a[i−2]−a[i]]+3∗b[i−2]+b[i]/3)
然后让
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]从上面的4个转移方程中取
m
a
x
max
max。
但是
n
∗
m
=
1
0
8
n*m=10^8
n∗m=108,所以开
1
e
8
1e8
1e8大小的
l
o
n
g
l
o
n
g
long\ long
long long会
M
L
E
MLE
MLE,
从上面的转移方程可以看到,
d
p
[
i
]
dp[i]
dp[i]的转移只用到了
d
p
[
i
−
1
]
、
d
p
[
i
−
2
]
、
d
p
[
i
−
3
]
dp[i-1]、dp[i-2]、dp[i-3]
dp[i−1]、dp[i−2]、dp[i−3],所以可以用滚动数组,对
i
i
i这一维滚动,周期是
4
4
4。这样的时间复杂度是
O
(
n
∗
m
)
O(n*m)
O(n∗m),空间复杂度是
O
(
m
)
O(m)
O(m),这样就能过了。
//AC code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e4+7,M=4;
#define I(t) ((t+M)%M)
int n,m,a[N];
LL b[N],dp[M][N],ans;
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
for(int i=1;i<=n+2;i++){
for(int j=1;j<=m;j++){
dp[I(i)][j]=dp[I(i-1)][j];//1
if(j-a[i]>=0)dp[I(i)][j]=max(dp[I(i)][j],dp[I(i-1)][j-a[i]]+b[i]);//2
if(i>1){
if(j-a[i-1]>=0)dp[I(i)][j]=max(dp[I(i)][j],dp[I(i-2)][j-a[i-1]]+2*b[i-1]);//3
if(j-a[i-1]-a[i]>=0)dp[I(i)][j]=max(dp[I(i)][j],dp[I(i-2)][j-a[i-1]-a[i]]+2*b[i-1]+b[i]/2);//3
}
if(i>2){
if(j-a[i-2]>=0)dp[I(i)][j]=max(dp[I(i)][j],dp[I(i-3)][j-a[i-2]]+3*b[i-2]);//4
if(j-a[i-2]-a[i]>=0)dp[I(i)][j]=max(dp[I(i)][j],dp[I(i-3)][j-a[i-2]-a[i]]+3*b[i-2]+b[i]/3);//4
}
ans=max(ans,dp[I(i)][j]);
}
}
cout<<ans;
}
减小常数的方法: 使用了滚动数组,要进行 1 e 8 1e8 1e8次取模会很慢,所以可以预处理模数; 可以根据转移方程的条件,例如 j − a [ i ] > = 0 j-a[i]>=0 j−a[i]>=0,删减无意义的循环。