题目描述
小 C 正在玩一款排兵布阵的游戏。在游戏中有 n 座城堡,每局对战由两名玩家来争夺这些城堡。每名玩家有 m 名士兵,可以向第 i 座城堡派遣 a_i名士兵去争夺这个城堡,使得总士兵数不超过 m。
如果一名玩家向第 i 座城堡派遣的士兵数严格大于对手派遣士兵数的两倍,那么这名玩家就占领了这座城堡,获得 i 分。
现在小 C 即将和其他 s 名玩家两两对战,这 s 场对决的派遣士兵方案必须相同。小 C 通过某些途径得知了其他 s 名玩家即将使用的策略,他想知道他应该使用什么策略来最大化自己的总分。
由于答案可能不唯一,你只需要输出小 C 总分的最大值。
对于 100% 的数据:1≤s≤100,1≤n≤100,1≤m≤20000,对于每名玩家 ai≥0, ∑ i = 1 n a i ≤ m \sum\limits_{i=1}^n a_i \le m i=1∑nai≤m
题目分析
数据范围看起来很大但其实就是分组背包裸题,复杂度为
O
(
n
m
s
)
O(nms)
O(nms)但常熟很小所以能过
预处理出a[i][k]表示对第i座城堡第k小的出兵数
将每个城堡看成一个组,每个组共s个物品,体积和价值分别为
a
[
i
]
[
k
]
∗
2
+
1
a[i][k]*2+1
a[i][k]∗2+1和
k
∗
i
k*i
k∗i
const int maxN=210;
const int maxM=40010;
int s,n,m;
int a[maxN][maxN];
int dp[maxM];
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 i=1;i<=n;++i)
for(int j=m;j>=0;--j)
for(int k=1;k<=s;++k)
{
if(j<a[i][k]*2+1) break;
dp[j]=max(dp[j],dp[j-a[i][k]*2-1]+k*i);
}
int ans=0;
for(int i=1;i<=m;++i)
ans=max(ans,dp[i]);
printf("%d",dp[m]);
return 0;
}