题目链接
这是一个DP问题,状态表示:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示,前
i
−
1
i-1
i−1集都决策完毕后,到达第
i
i
i集且当前剩余观看人数为
j
j
j时,最大收益
很明显可以得到:
①
d
p
[
i
+
1
]
[
j
/
d
[
i
]
]
=
m
a
x
(
d
p
[
i
+
1
]
[
j
/
d
[
i
]
]
,
d
p
[
i
]
[
j
]
+
p
[
i
]
×
j
)
dp[i+1][j/d[i]]=max(dp[i+1][j/d[i]],dp[i][j]+p[i] \times j)
dp[i+1][j/d[i]]=max(dp[i+1][j/d[i]],dp[i][j]+p[i]×j)
②
d
p
[
i
+
1
]
[
j
]
=
d
p
[
i
]
[
j
]
dp[i+1][j]=dp[i][j]
dp[i+1][j]=dp[i][j]
即由
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]这个状态可以推导出两个新的状态,分别是第
i
+
1
i+1
i+1层,人数不变,即上一集没有插播广告,即没有收益,因此得到②式
第
i
+
1
i+1
i+1层,人数发生变化(减少),即上一集中插播了广告,上一集由
j
j
j个人,因此插播广告后人数为
j
/
d
[
i
]
j/d[i]
j/d[i],新获得的收益为
p
[
i
]
×
j
p[i] \times j
p[i]×j,因此有①式
如果直接定义这么大一个二维数组会同时MLE和TLE。但其实没有必要,首先第
i
+
1
i+1
i+1层的状态完全由第
i
i
i层推出,因此可以用滚动数组,递推方向从前向后,MLE解决了。但是两层循环遍历依然会TLE。是因为我们遍历了很多用不到的
j
j
j,地推过程中出现的
j
j
j的取值是
⌊
m
/
a
⌋
\lfloor m/a \rfloor
⌊m/a⌋和
⌊
⌊
m
/
a
⌋
/
b
⌋
\lfloor\lfloor m/a\rfloor /b\rfloor
⌊⌊m/a⌋/b⌋,而
⌊
⌊
m
/
a
⌋
/
b
⌋
=
⌊
m
/
(
a
×
b
)
⌋
\lfloor\lfloor m/a\rfloor /b\rfloor =\lfloor m/(a\times b) \rfloor
⌊⌊m/a⌋/b⌋=⌊m/(a×b)⌋,也就是说,所有
j
j
j的取值都在
m
m
m的范围内,且数量不多,只需要预处理出来,就可以减少内层循环的次数。数量为根号级别,复杂度为
n
m
n\sqrt m
nm
注意使用 long long
⌊
⌊
m
/
a
⌋
/
b
⌋
=
⌊
m
/
(
a
×
b
)
⌋
\lfloor\lfloor m/a\rfloor /b\rfloor =\lfloor m/(a\times b) \rfloor
⌊⌊m/a⌋/b⌋=⌊m/(a×b)⌋简易证明:
⌊
m
/
(
a
×
b
)
⌋
\lfloor m/(a\times b) \rfloor
⌊m/(a×b)⌋表示
m
m
m中含有多少个
a
×
b
a\times b
a×b
⌊
m
/
a
⌋
\lfloor m/a\rfloor
⌊m/a⌋表示
m
m
m中含有多少个
a
a
a,设
⌊
m
/
a
⌋
=
l
\lfloor m/a\rfloor=l
⌊m/a⌋=l
则
m
m
m中包含
a
×
b
a\times b
a×b个数可表示为
⌊
a
×
l
a
×
b
⌋
\lfloor\frac{a\times l}{a\times b}\rfloor
⌊a×ba×l⌋即
⌊
l
b
⌋
\lfloor\frac{l}{b}\rfloor
⌊bl⌋(因为是
a
×
b
a\times b
a×b的倍数,则一定是
a
a
a的倍数,而
m
m
m以内
a
a
a的最大倍数是
a
×
l
a\times l
a×l,因此上限不写m而写成
a
×
l
a\times l
a×l)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int p[N], d[N];
typedef long long ll;
bool vis[N];
int a[N], ind;
int n, m;
ll dp[N];
// #define LOCAL
int main(){
#ifdef LOCAL
freopen("in", "r", stdin);
freopen("out", "w", stdout);
#endif
scanf("%d %d", &n, &m);
memset(vis, 0, sizeof vis);
for (int i = 1; i <= n; i++)scanf("%d", p + i);
for (int i = 1; i <= n; i++)scanf("%d", d + i);
ind = 0;
a[++ind] = 0;
for (int i = 1; i <= m; i++){
if (!vis[m / i]){
vis[m / i] = 1;
a[++ind] = m / i;
}
}
sort(a + 1, a + 1 + ind);
memset(dp, 0, sizeof dp);
for (int i = 1; i <= n; i++){
for (int j = 1; j <= ind; j++){
dp[a[j] / d[i]] = max(dp[a[j] / d[i]], dp[a[j]] + (ll)p[i] * (ll)a[j]);
}
}
ll ans = -1;
for (int i = 0; i <= m; i++)ans = max(ans, dp[i]);
cout << ans;
return 0;
}