1. 程式人生 > >【JZOJ A組】斬殺計劃

【JZOJ A組】斬殺計劃

Description

眾所周知,小J和小G是死對頭,一天小G帶領一群小弟找到了小J。
問題描述
小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

Sample Input

Sample Input1:
3 5
1 2 3

Sample Input2:
8 8
10 20 30 40 50 60 70 80

Sample Input3:
8 80
10 20 30 40 50 60 70 80

Sample Output

Sample Output1:
0 5

樣例說明
對2,3小弟使用複用型藥水和獵人藥水

Sample Output2:
16 23

樣例說明
使用16個腐敗藥水
在第3個腐敗藥水時拉10,攻擊力為1
在第6個腐敗藥水時拉20,攻擊力為2
在第9個腐敗藥水時拉30,攻擊力為3
在第16個腐敗藥水時拉50,攻擊力為2

Sample Output3:
-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

Hint

​提示
鑑於本題為簽到題直接輸出-1或者0,0都能獲得10分的好成績
請仔細閱讀題目,有些細節可能讓你損失很多的分數0.0
輸入規模較大,請使用較快的讀入方式

思路

PS:這題千萬不要用快讀!!!會出事!!!

這題是貪心。。。
首先我們可以用桶排排序,然後列舉使用腐敗藥水的個數,直到綜合大於等於m

然後貪心去掉一些東西即可

程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,at1,at2,at3,ans,p=-1,a[30077],t=0;
int main()
{
	freopen("zhanshajihua.in","r",stdin); freopen("zhanshajihua.out","w",stdout);
	scanf("%d%d",&n,&m);
	if(m==0)
	{
		printf("0 0"); return 0;
	}
	for(int i=1; i<=n; i++)
	{
		int x;
		scanf("%d",&x); a[x]++;
		int xx=x%3==0?3:x%3; t+=xx;
	}
	if(t<m)
	{
		printf("-1"); return 0;
	}
	int s=0;
	for(int i=1; i+2<=30001; i+=3)
    {
        ans+=a[i]; at1+=a[i];
        ans+=a[i+1]*2; at2+=a[i+1];
        ans+=a[i+2]*3; at3+=a[i+2];
        p++;
        if(ans>=m) break;
    }
	while(ans>=m+3&&at3) {at3--; ans-=3;}
	while(ans>=m+1&&at1) {at1--; ans-=1;} 
    while(ans>=m+2&&at2) {at2--; ans-=2;}
	printf("%d %d",p,(at1+at2)+at3*4+p);
}