[BJOI2019]排兵布阵

题目

原题地址

解说

蒟蒻刷\(DP\)题的时候刷到的好题。

首先这道题很显然是一个背包,每个城堡应该被看作物品,但主要问题就在于其消耗和价值分别是什么?经过一番思考我们发现每个城堡还需要考虑不同敌人的影响,而把城堡看作一个物品就没办法考虑上这一点,怎么办?换个思路,为何不把一个背包看作一组物品呢?

由于我们每一轮攻击中投入士兵的分配都是不变的,所以在每城堡投入一定的兵力时\(s\)轮下来的累计收入是可以预处理的,这样的话我们不妨把投入兵力看作消耗,累计收入看作价值,并且不难发现每个城堡的各个物品间是不能同时选择的(毕竟一个城堡只能选择一个特定的兵力投入),正好形成了一个非常裸的分组背包模型!

时间复杂度方面,预处理为\(O(ns)\)的,跑分组背包时理论上为\(O(nsm)\),极限数据时似乎达到了\(10^8\)水平,但事实上由于常数挺小的而且循环背包容量时可以不用跑满,所以还是可以接受的。

具体一些细节见代码

代码

#include<bits/stdc++.h>
#define re register
using namespace std;
int s,n,m,num[100+3][100+3],f[20000+3],ans;
vector<int> city[100+3];
struct thing{
	int cost,val;
};
vector<thing> group[100+3];
int main(){
	scanf("%d%d%d",&s,&n,&m);
	for(re int i=1;i<=s;i++){
		for(re int j=1;j<=n;j++){
			scanf("%d",&num[i][j]);
			num[i][j]=num[i][j]*2+1;
		}
	}
	for(re int i=1;i<=n;i++){
		for(re int j=1;j<=s;j++) city[i].push_back(num[j][i]);
		sort(city[i].begin(),city[i].end());
	}
	for(re int i=1;i<=n;i++)
		for(re int j=0;j<city[i].size();j++)
			group[i].push_back((thing){city[i][j],i*(j+1)});
	for(re int g=1;g<=n;g++){
		for(re int j=m;j>=0;j--){
			for(re int i=0;i<group[g].size();i++){
				if(j>=group[g][i].cost) f[j]=max(f[j],f[j-group[g][i].cost]+group[g][i].val);
				else break;
			}
		}
	}
	printf("%d\n",f[m]);
	return 0;
}

幸甚至哉,歌以咏志。

posted @ 2020-10-07 12:04  DarthVictor  阅读(218)  评论(3编辑  收藏  举报
莫挨老子!