T3补兵
题目描述
对于一个DOTA玩家,补兵个数(Creep Score)是衡量一名选手能力的重要指标,特别是打路人局的时候,补兵能力就更加关键了,因为常常会有队友和你抢补刀,比如,队友操控的老鹿在开大收兵,如果你操控的是幽鬼,就需要在老鹿的AOE中偷偷补上几刀来保证自己的发育。
我们自己建立一个模型来大致模拟以下情况:
现在有n个小兵,每个小兵有自己的血量Ai(血量一定是正整数),你和老鹿轮流对小兵进行攻击。每次,你可以选择对某个小兵造成1点伤害(或者你可以选择不作为),接着,老鹿会对所有小兵造成1点AOE伤害,如此往复,直到所有小兵都死亡(血量变成0)。如果你对某个小兵造成致命伤害(使他的血量从1变成0).那么你就补刀成功了!
对于给定的情形,你需要计算你最多可以补刀多少的小兵。
输入格式
本题有多组测试数据,第一行为一个整数T,表示测试组数。 对于每一组数据,第一行一个整数N,表示小兵的个数,随后第二行N个正整数,表示每个小兵的血量。
输出格式
对于每一组数据,输出一个整数M,表示补兵的最大数量。
输出格式
对于30%的数据,N ≤\leq≤ 100,对于50%的数据,N ≤\leq≤ 500,T ≤\leq≤ 30, a[i]a[i]a[i] ≤\leq≤ 500,对于1000%的数据,1 ≤\leq≤ N ≤\leq≤ 500,1 ≤\leq≤ T ≤\leq≤ 70,1 ≤\leq≤ a[i]a[i]a[i] ≤\leq≤ 1000。
样例
样例输入
1
5
5 5 5 5 5
样例输出
2
资源与时间限制
内存:256MB
时间:1s
正解思路
正解代码
#include<bits/stdc++.h>
using namespace std;
const int N=1086;
int cnt[N],c[N],f[N][N],a[N],sta[N];
int main()
{
freopen("cs.in","r",stdin);
freopen("cs.out","w",stdout);
int t;
cin>>t;
while(t--)
{
int n,maxx=0;
cin>>n;
memset(cnt,0,sizeof(cnt));
memset(c,0,sizeof(c));
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
{
cin>>a[i];
++cnt[a[i]];
maxx=max(maxx,a[i]);//找到补兵攻击的最大次数
}
int top=0;
for(int i=1;i<=maxx;i++)
{
if(cnt[i]==0) sta[++top]=i;
else{
while(cnt[i]>1&&top>0)
{
c[sta[top--]]=i;
--cnt[i];
}
c[i]=i;
}
}
int ans=0;
for(int i=1;i<=maxx;++i)
{
for(int j=0;j<=i;++j)
{
if(j>0) f[i][j]=f[i-1][j-1];
if(c[i]!=0&&j+c[i]-i<i)
{
f[i][j]=max(f[i][j],f[i-1][j+c[i]-i]+1);
}
ans=max(ans,f[i][j]);
}
}
cout<<ans<<endl;
}
return 0;
}