原题传送门
这是我做过的最easy的省选题!!!
按照以往的套路,先想部分分
发现s=1的情况特别水,小学生等级的01背包水过50分
时间复杂度
O
(
n
m
)
O(nm)
O(nm)
s>1呢
猜想时间复杂度套上一个s,为
O
(
n
m
s
)
O(nms)
O(nms)
但是算了一算需要2s时限,有点慌,但是应该是跑不满2s的,可以一试
发现对于每一个城堡,都有s个玩家
其实可以按照这个城堡针对s个玩家打败他们所需的人数排个序
从小到大枚举即可
d
p
数
组
:
d
p
[
m
]
表
示
用
了
m
个
人
获
得
的
最
大
价
值
dp数组:dp[m]表示用了m个人获得的最大价值
dp数组:dp[m]表示用了m个人获得的最大价值
转
移
方
程
:
d
p
[
j
]
=
m
a
x
(
d
p
[
j
]
,
d
p
[
j
−
(
a
[
i
]
[
k
]
∗
2
+
1
)
]
+
k
∗
i
)
转移方程:dp[j]=max(dp[j],dp[j-(a[i][k]*2+1)]+k*i)
转移方程:dp[j]=max(dp[j],dp[j−(a[i][k]∗2+1)]+k∗i)
i
对
应
n
,
j
对
应
m
,
k
对
应
s
i对应n,j对应m,k对应s
i对应n,j对应m,k对应s
Code:
#include <bits/stdc++.h>
#define maxn 200
#define maxm 20010
using namespace std;
int s, n, m, a[maxn][maxn], dp[maxm];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
int main(){
s = read(), n = read(), m = read();
for (int i = 1; i <= s; ++i)
for (int j = 1; j <= n; ++j) a[j][i] = read();
for (int i = 1; i <= n; ++i){
sort(a[i] + 1, a[i] + 1 + s);
for (int j = m; j; --j)
for (int k = 1; k <= s; ++k)
if (j >= (a[i][k] << 1) + 1) dp[j] = max(dp[j], dp[j - (a[i][k] << 1) - 1] + k * i);
}
printf("%d\n", dp[m]);
return 0;
}

本文分享了一个省选竞赛中极为简单的题目解析,通过01背包问题的基础思路,优化算法至O(nms),实现对每个城堡s个玩家的最优解求解。文章详细介绍了从部分分策略出发,逐步优化至最终算法的过程,并提供了完整的C++代码实现。
1038

被折叠的 条评论
为什么被折叠?



