洛谷 肮脏的牧师 题解

  1 题目描述
  2 
  3 Yumis最近在玩炉石传说。
  4 
  5 在炉石传说中脏牧有一张一费卡片(一费就是使用要消耗1点法力水晶),叫做疯狂药水,这个的效果是将一个敌方场上攻击小于等于2的随从拉到自己的战场内。
  6 
  7 还有一张四费卡片叫做暗影狂乱,这个的效果是将一个敌方场上攻击小于等于3的随从拉到自己的战场内。
  8 
  9 还有一张一费卡片就是缩小药水,这个的效果是将敌人全场的随从攻击力下降3点。
 10 
 11 你PY了炉石的GM所以你有了无数张的这三种卡片,但是GM告诉你缩小药水是这个牌比较不好创建,为了为GM着想你必须在使用最少的缩小药水的情况下A爆对手的脸。
 12 
 13 现在你的对手场上有n个随从,每个随从的攻击力是ki点。
 14 
 15 你的对手有m点血量。
 16 
 17 而你现在要做的就是将敌方的场上的随从拉过来自己的场上并攻击对手(每一个随从只能攻击一次,攻击力为你拉过来的时候随从剩余的攻击力),A爆对面的脸(将对面的血打到0点及以下)。
 18 
 19 输入输出格式
 20 
 21 输入格式:
 22 第一行用一个空格隔开的两个整数n,m分别代表敌方场上的随从数量和你对手的血量。
 23 
 24 第二行n个整数每两个整数之间用一个空格隔开,分别代表敌方场上每一个随从的攻击力ki。
 25 
 26 输出格式:
 27 一行如果可以A爆则输出最少使用的缩小药水的数量和此时使用的法力水晶,两个数据之间用一个空格隔开(如果有多个答案则输出消耗法力水晶最少的答案)。
 28 
 29 否则输出“Human Cannot Win Dog”(没有双引号)
 30 
 31 输入输出样例
 32 
 33 输入样例#1: 复制
 34 3 5
 35 1 2 3 
 36 输出样例#1 37 0 5
 38 输入样例#2 39 8 8
 40 10 20 30 40 50 60 70 80
 41 输出样例#2 42 16 23
 43 输入样例#3 44 8 80
 45 10 20 30 40 50 60 70 80
 46 输出样例#3 47 Human Cannot Win Dog
 48 说明
 49 
 50 样例说明1:
 51 
 52 敌方场上有3只随从,敌方有5点血量
 53 
 54 我们把3攻随从和2攻随从拉过来花费0个缩小药水和5点耗费(一张疯狂药水一个暗影狂乱(1+4 = 5))伤害足够击杀对方。
 55 
 56 样例说明2:
 57 
 58 使用16个缩小药水(下面数据后面第一个括号指拉过来的时候伤害为多高 ,第二个括号表示拉过来的时候使用多少的缩小药水)
 59 
 60 拿10(1)(3)、202)(6)、303)(9)、502)(16)攻的怪物总共造成8点伤害 刚好A爆!
 61 
 62 Easy : 保证 0 < n <= 10 并且不存在用到暗影狂乱和缩小药水的情况 20%
 63 
 64 Normal :保证 0 < n <= 10 并且不存在用到缩小药水的情况 20%
 65 
 66 Hard :保证 0 < n <= 10 30%
 67 
 68 Extra:保证0 <= n <= 5000000(6个0),最大攻击力小于30000 30%
 69 
 70 保证 0 < n <= 5000000 0 < ki <=30000 0<=m<=5000000 (6个0)
 71 
 72 #include <iostream>
 73 #include <cstdio>
 74 #include <cstring>
 75 #include <algorithm>
 76 using namespace std;
 77 inline int read(){
 78     int num=0,f=1; char c=getchar();
 79     while(!isdigit(c)){if(c=='-') f=-1; c=getchar();}
 80     while(isdigit(c)){num=(num<<1)+(num<<3)+(c^48); c=getchar();}
 81     return num*f;
 82 }
 83 #define maxn 30010
 84 int n,m,use,sum,cnt[maxn];
 85 int main(){
 86     n=read(); m=read();
 87     for(int i=1;i<=n;i++){
 88         int x; x=read();
 89         cnt[x]++;
 90     }
 91     int u1=cnt[1],u2=cnt[2],u3=cnt[3];
 92     sum=u1*1+u2*2+u3*3;
 93     for(int i=4;i+2<=maxn and sum<m;i+=3){
 94         u1+=cnt[i]; u2+=cnt[i+1]; u3+=cnt[i+2];
 95         use++;
 96         //sum=1*u1+2*u2+3*u3;
 97         sum+=cnt[i]+cnt[i+1]*2+cnt[i+2]*3;
 98     }
 99     while(sum>=m+3 and u3) sum-=3,u3--;
100     while(sum>=m+2 and u2) sum-=2,u2--;
101     while(sum>=m+1 and u1) sum-=1,u1--;
102     if(sum<m) cout<<"Human Cannot Win Dog";
103     else cout<<use<<" "<<(u3<<2)+u1+u2+use;
104 }
105 
106 思路是利用筛的思想,可以归纳一下。
107 筛法无疑是利用了题目中的除的条件,最终加上的攻击力总是1 ,23.
108 所以可以筛攻击力,从1到max。筛的过程中不断更新缩小药水(限制变量)。
109 最后若sum比m多1,则删去任意一个为一的攻击力(以此类推)。
110 
111 所以筛的思想可用于,给定几个定值,之后其他量都需变化成这几个值。

 

posted @ 2017-10-30 09:54  TimDucan  阅读(320)  评论(0编辑  收藏  举报