题目描述
牛牛悄悄溜进了敌人的阵地,准备破坏敌人的城墙和防御法阵,破坏防御法阵可以给牛牛带来经验值。
敌人的城墙分为N块,这些城墙排成一排,不成环。牛牛可以破坏M块城墙,他可以从任意一点开始不断破坏两侧相邻的城墙。
每块城墙下方刻有诸多防御法阵。每个法阵需要耗费不同的时间来破坏。同时,为了防止对手发现,牛牛在每块城墙下仅能停留T秒。经过的时间忽略不计。
破坏每个法阵会带来不同的经验值。并且,当相邻的城墙已经被破坏时,经验值会增加。
举例来讲,假设牛牛在某块城墙收获k点经验值,但该城墙一侧(按照破坏顺序的规则,显然只有一侧可能被破坏)收获经验值为k1,那么这块城墙的经验数变为k + k1 。而当某块城墙一侧有n块城墙被破坏,其实际收获的经验值为 k + k1 + k2+. . . +kn
一段城墙得到的经验值为这一段城墙中每一段得到的经验值之和。
显然,最终的经验值还和破坏顺序有关。
现在,牛牛想知道他能得到的经验值最大是多少。
Note:上述的k1, k2, . . . , kn是指城墙左侧(或右侧)连续n个城墙被破坏时获得的经验值。
输入
第一行三个整数 N, M, T,含义见题目描述。
接下来 N行,每行首先有正整数 K表示该块城墙下方的法阵数量,接下来 2K 个正整数,依次是第 1 个法阵破坏后的经验值 vi,第 1 法阵破坏的用时 ti。
第 2 个法阵破坏后的经验值和破坏用时,直到第 K 个法阵。
输出
一个正整数,表示牛牛能够得到的最大经验值。
样例
样例输入
【样例 1 输入】
5 3 5
2 1 5 9 2
3 1 10 1 2 2 3
1 9 4
3 1 10 5 2 1 4
4 8 8 9 9 7 7 6 1
【样例 2 输入】
5 5 5
2 1 5 9 2
3 1 10 1 2 2 3
1 9 4
3 1 10 5 2 1 4
4 8 8 9 9 7 7 6 1
样例输出
【样例 1 输出】
52
【样例 2 输出】
223
提示
【样例 1 说明】
城墙共 5 段,每段在 5 秒内破坏,不计相邻城墙的破坏效果加成的情况下,依次 能收到最多 9,3,9,5,6 点经验值。破坏 3 段,此时选择先破坏中间的城墙获得 9 点 经验值,再依次获得 5,6 点经验值,最终能够造成最大 52 点经验值。计算过程 如下 9+(9+5)+[(9+9+5)+6]=52。
【数据范围】
对于 20% 的数据,满足 K = 1
对于另外 20% 的数据,满足 M = 1
对于额外 20% 的数据,满足 M ≤ 3, K ≤ 5
对于 100% 的数据,满足0 < K ≤ 50,0 < T ≤ 200,0 < M < 30,0 < N < 10000, 0 < vi,ti ≤ 50
保证答案在 long long 范围内。
分析
1.对于每个城墙下面的法阵,可以用01背包求最大收益
2.由于只能破坏相邻的城墙,故可以用区间dp处理
g[i][j]
表示区间[l,r]的最大经验值
g
[
l
]
[
r
]
=
m
a
x
(
g
[
l
]
[
r
−
1
]
∗
2
+
g
[
r
]
[
r
]
,
g
[
l
+
1
]
[
r
]
∗
2
+
g
[
l
]
[
l
]
)
g[l][r] = max(g[l][r - 1] * 2 + g[r][r],g[l + 1][r] * 2 + g[l][l])
g[l][r]=max(g[l][r−1]∗2+g[r][r],g[l+1][r]∗2+g[l][l])
时间复杂度 O(n * k^2 + nm)
代码
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 10000 + 10,M = 200 + 10,K = 50 + 10;
int n,m,t,k;
int v[K],w[K];
int f[M];
map<int,LL> g[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin >> n >> m >> t;
for(int i = 1;i <= n;i++){
cin >> k;
for(int j = 1;j <= k;j++) cin >> w[j] >> v[j];
memset(f,0,sizeof f);
for(int j = 1;j <= k;j++)
for(int p = t;p >= v[j];p--)
f[p] = max(f[p],f[p - v[j]] + w[j]);
g[i][i] = f[t];
}
for(int len = 2;len <= m;len++)
for(int i = 1;i + len - 1 <= n;i++){
int l = i,r = i + len - 1;
g[l][r] = max(g[l][r - 1] * 2 + g[r][r],g[l + 1][r] * 2 + g[l][l]);
}
LL res = 0;
for(int i = 1;i + m - 1 <= n;i++) res = max(res,g[i][i + m - 1]);
cout << res;
return 0;
}