【题解】P5322 [BJOI2019] 排兵布阵(DP,背包)
【题解】P5322 [BJOI2019] 排兵布阵
挺开心的,毕竟这是我为数不多自己做出的蓝题之一。
题目链接
题意概述
这道题的题意很清楚,所以这里直接摘抄原题题面。
小 C 正在玩一款排兵布阵的游戏。在游戏中有
如果一名玩家向第
现在小 C 即将和其他
由于答案可能不唯一,你只需要输出小 C 总分的最大值。
思路分析
刚开始想了一个前缀和差分套 01 背包的做法。
定义
那么对于一个输入的
最后对于每一个
定义
可以发现实际上这是一个 01 背包,枚举第
直接转移即可。
分析一下时间复杂度:枚举
所以总复杂度:
考虑如何优化。
如果
观察数据范围可以发现,
其实是可以的。
既然我们直接枚举士兵个数不成,不妨换个角度。我们枚举可以占领几次城堡,也就是在这个城堡上战胜了多少个敌人。
那么我们只需要知道战胜了
显然选择士兵个数要遵循的原则是:能小则小。即在满足条件的情况下,选最少的士兵。
这个是显然的,因为如果你选的更大就会使得多选的士兵浪费,从而不一定达到最优解。
所以对于战胜了
那么我们对每一座城堡上所有敌人派遣的士兵个数排序,
综上,对于
时间复杂度:
易错点
-
在刚开始输入的时候,由于
表示的是表示的是第 个城堡上所有敌人派遣第 小的士兵数量。但输入相对于这个是反的,所以刚开始应该输入的是 。 -
对于一个
,若没有使用滚动数组,则刚开始要继承 。
代码实现
//luoguP5322
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=105;
const int maxm=2e4+10;
int a[maxn][maxm<<1],dp[maxn][maxm<<1];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
int main()
{
int s,n,m;
s=read();n=read();m=read();
for(int i=1;i<=s;i++)
{
for(int j=1;j<=n;j++)
{
int x=read();
a[j][i]=x;//bug:a[i][j]=x;
}
}
for(int i=1;i<=n;i++)sort(a[i]+1,a[i]+s+1);
for(int i=1;i<=n;i++)
{
for(int j=m;j>=0;j--)
{
dp[i][j]=dp[i-1][j];//bug:forget
//要在枚举 k 的循环外继承。
for(int k=1;k<=s;k++)
{
if(j>=a[i][k]*2+1)dp[i][j]=max(dp[i][j],dp[i-1][j-a[i][k]*2-1]+k*i);
}
}
}
int ans=0;
for(int i=0;i<=m;i++)ans=max(ans,dp[n][i]);
cout<<ans<<'\n';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?