JZOJ5937. 【NOIP2018模拟10.30】斩杀计划

Description

小G有n个小弟,第i个小弟有ai点攻击力,小G有m点血量。
小J在小G找小第的时间里去找小Z学到了膜法,他在大战前配置了三种魔法药水
1:复用型药水:花费1法力值,选择小G的攻击力小于等于2的一个小弟让他跟随自己(变为自己的小弟并且攻击力和属于小G时一样)
2:猎人药水:花费4法力值,选择小G的攻击力小于等于3的一个小弟让他跟随自己
3:腐败药水:花费1法力值,使小G所有小弟攻击力降低三点(使用前两种魔法将小弟拉到自己阵营时小弟攻击力就是当前的攻击力,即小J的小弟攻击力只能为1,2,3)
为了向小G展现自己的力量,他打算在召集到一些小弟后发动攻击(每个小弟打一次)直接秒杀小G(攻击力大于等于m)
由于智商有限,小J在配置腐败药水时会花费很大精力,他需要知道自己最少使用多少腐败药水,并在腐败药水数量最小的情况下花费最小的法力值

Input

第一行两个正整数n,m表示小G的小弟数量和血量
第二行n个正整数表示小G所有小弟的攻击力

Output

一行两个整数表示最小的腐败药水数量和在腐败药水最小的情况下法力值花费,如果无论如何都无法战胜,输出一个整数-1

Data Constraint

测试点1,2: n≤10并且最优情况不需要使用腐败药水和猎人药水
测试点3,4: n≤10并且最有情况不需要使用腐败药水
测试点5,6,7: n≤10
测试点8,9,10: n≤5000000,最大攻击力小于等于30000
对于所有数据 0≤m≤5000000

题解

因为要使用的腐败药水最少,
所以先优先考虑如何用最小的腐败药水。
就是枚举腐败药水的数量,
能拉的小弟就拉过来,当第一次超过m以后,
也算是说当前就是腐败药水的最小值。
接下来就是要考虑最小的法力值了,
显然,猎奇药水是不值得的,贪心先去掉所以需要猎奇药水的,但必须保证去掉之后依然是超过m的。
接下来,在复制型药水中,相比能力值为2的小弟,能力值为1的小弟更加不值钱,
于是呢,下一个去掉能力值为1的小弟。
最后如果还有多的,才考虑去掉能力值为2的小弟。

code

#include 
#include 
#include 
#include 
#include 
#define N 30008
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
	n=0;
	ch=G();
	while((ch<'0' || ch>'9') && ch!='-')ch=G();
	int w=1;
	if(ch=='-')w=-1,ch=G();
	while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
	n*=w;
}

int n,m,x,t[N],sum,s[3],ans;

int main()
{
	freopen("zhanshajihua.in","r",stdin);
	freopen("zhanshajihua.out","w",stdout);
	
	read(n);read(m);ans=-1;
	for(int i=1;i<=n;i++)read(x),t[x]++;
	for(int i=0;i<=10000;i++)
	{
		x=i*3;s[0]=s[0]+t[x+1];s[1]=s[1]+t[x+2];s[2]=s[2]+t[x+3];
		sum=s[0]+s[1]*2+s[2]*3;
		if(sum>=m)
		{
			printf("%d ",i);ans=i;
			break;
		}
	}
	if(ans<0)
	{
		printf("-1"); 
		return 0;
	}
	for(;sum-3>=m && s[2];s[2]--)sum=sum-3;
	for(;sum-1>=m && s[0];s[0]--)sum=sum-1;
	for(;sum-2>=m && s[1];s[1]--)sum=sum-2;
	ans=ans+s[2]*4+s[1]+s[0];
	printf("%d\n",ans);
	return 0;
}

你可能感兴趣的:(题解,贪心)