JZOJ-senior-5937. 【NOIP2018模擬10.30】斬殺計劃
Time Limits: 1000 ms Memory Limits: 262144 KB
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
輸入規模較大,請使用較快的讀入方式
Solution
- 輸入時記錄下有每個小弟需要用藥水的次數以及最終攻擊力
- 二分求出使用腐敗藥水的最少次數
- 使得在這個次數內能拉過來的小弟的總攻擊力大於
- 最後貪心地刪去多餘的小弟
- 優先刪去3(花費4,不值),然後刪去 1(相同代價下攻擊力較小),最後刪去 2
Code
#include<algorithm>
#include<cstdio>
#include<cctype>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int M=1e4+5;
int n,m,x,mx,mag,s[M],a[M][4];
inline void read(int &n)
{
int x=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
n=w?-x:x;
}
void get_magic(int cs)
{
int more=s[cs]-m;
mag=a[cs][1]+a[cs][2]+4*a[cs][3];
if(a[cs][3])
{
int k=min(more/3,a[cs][3]);
more-=3*k,mag-=4*k;
}
if(a[cs][1])
{
int k=min(more,a[cs][1]);
more-=k,mag-=k;
}
if(a[cs][2])
{
int k=min(more/2,a[cs][2]);
more-=2*k,mag-=k;
}
}
int main()
{
freopen("zhanshajihua.in","r",stdin);
freopen("zhanshajihua.out","w",stdout);
read(n),read(m),mx=0;
fo(i,1,n)
{
read(x);
if(!x) continue;
int p=(x-1)/3; x-=3*p;
int q=x<=2?1:4; mx=max(p,mx);
s[p]+=x,++a[p][x];
}
fo(i,1,mx)
{
s[i]+=s[i-1];
a[i][1]+=a[i-1][1];
a[i][2]+=a[i-1][2];
a[i][3]+=a[i-1][3];
}
int l=0,r=mx+1;
while(l<r)
{
int mid=(l+r)>>1;
if(s[mid]>=m) r=mid;
else l=mid+1;
}
if(l==mx+1) {printf("-1"); return 0;}
get_magic(l);
printf("%d %d",l,mag+l);
}