「HDU3640」I,Zombie

题意:原题在这
 
原创翻译:
有一份只有一行的植物大战僵尸地图:
                50hp的普通僵尸。
                两种植物:豌豆射手(10hp)和土豆雷(一次性)。
 
 
每秒的操作步骤如下:
          1.在最右侧的草皮中逐个放置0<=num的僵尸 (在最右边草皮的右边,即地图之外)
          2.判断每一个幸存的僵尸,是否站在一个豌豆射手身上:
            if true,攻击这个豌豆射手,豌豆射手hp -1.豌豆射手的hp在那一刻可能是负值,但它仍然活着!
            if false,向左移动一格。
          3.如果地图上还有僵尸,每一个幸存的豌豆射手都会向最早放置的僵尸射击(僵尸每被锤一下hp -1,僵尸的hp在那一刻可能是负值,但它仍然活着!)
          4.如果在土豆雷的草皮中有僵尸,那么土豆雷爆炸,这个草皮中所有僵尸的hp变为0。
          5.非正hp的植物和僵尸消失(直到现在它们已经死亡)

 

请根据所给的地图,求僵尸胜利的最小个数.

 

方法及思路:全网唯一一篇题解在这
模拟,主要有三个问题要维护,一是植物的长度,二是最右边的植物种类,三是僵尸距离最近的植物的步数。
 
如果僵尸碰到了地雷,那么下一回合可以认为僵尸的最左位置为炸弹的左边。(僵尸左移)
 
如果碰到的不是地雷,则不停向左统计植物个数,直到遇到第一个炸弹
 
然后二分可以吃掉这些植物的最少僵尸个数,二分时要根据条件进行模拟。
 
 
其余详见代码注释↓
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 int T;
  8 int P,M,len,Zombie,Step;
  9 char plant[150];
 10 
 11 void init(char p[])
 12 {
 13     Zombie=P=M=0;
 14     len=strlen(p)-1;
 15     for(int i=0;i<=len;i++)
 16     {
 17         if(p[i]=='P')
 18             P++;
 19         else
 20             M++;
 21     }
 22 }
 23 
 24 int solve(int sum,int plnt,int zom)//植物总数,豌豆个数,僵尸个数
 25 {
 26     int flag=Step;//距离最近植物的步数
 27     int plnt_life=10,zom_life=50;//初始生命值
 28     while(plnt>0 && zom>0)
 29     {
 30         if(flag>0)//还没到最近的植物
 31         {
 32             flag--;//走一步
 33             zom_life-=sum;//这个僵尸会被所有植物锤
 34         }
 35         else//到了最近的植物
 36         {
 37             plnt_life-=zom;//这个豌豆会被所有僵尸锤
 38             zom_life-=sum;//这个僵尸会被所有植物锤
 39         }
 40         if(plnt_life<=0)//死了一个射手
 41         {
 42             plnt_life=10;
 43             sum--; plnt--;
 44             flag=1;
 45         }
 46         if(zom_life<=0)//死了一个僵尸
 47         {
 48             zom_life=50;
 49             zom--;
 50         }
 51     }
 52     if(plnt<=0 && zom>0)//僵尸赢辣
 53         return 1;
 54     if(plnt<=0 && zom<=0)//都死光了
 55         return 0;
 56     if(plnt>0)//植物还活着
 57         return -1;
 58 }
 59 
 60 int main()
 61 {
 62     cin>>T;
 63     for(int cas=1;cas<=T;cas++)
 64     {
 65         cin>>plant;
 66         init(plant);
 67         if(plant[len]=='M')//有地雷
 68         {
 69             len--;//先牺牲一个僵尸同归于尽
 70             Zombie++;//僵尸前进一步
 71             Step=2;
 72         }
 73         else
 74             Step=1;
 75         while(len>=0)//只要还没到brain处
 76         {
 77             if(plant[len]=='M')//前面是地雷
 78             {
 79                 if(Step>1)//还没到地雷
 80                 {
 81                     Step--;//走一步
 82                     if(P>=50) Zombie++;//并且打得过,那么干死一个僵尸
 83                     continue;
 84                 }
 85                 else
 86                     Zombie++;//死一个僵尸
 87                 M--; len--;//消耗一颗地雷
 88                 Step=2;
 89             }
 90 
 91             else//前面是豌豆射手
 92             {
 93                 //从后往前统计豌豆个数
 94                 int pNum=0;
 95                 for(int i=len;i>=0;i--)
 96                 {
 97                     if(plant[i]=='M')
 98                         break;
 99                     else
100                         pNum++;
101                 }
102                 //二分最少僵尸个数
103                 int left=1,right=300,mid;
104                 while(left<right)//直至二分出答案
105                 {
106                     mid=(left+right)>>1;
107                     if(solve(P,pNum,mid)>0)//如果这种情况下僵尸赢
108                         right=mid;
109                     else
110                         left=mid+1;
111                 }
112                 Zombie+=left;//加上二分出的答案
113                 P-=pNum;
114                 len-=pNum+1;
115                 Step=2;
116             }
117         }
118         if(plant[0]=='M')//判断一开始是地雷
119             Zombie++;
120         printf("Case %d: %d\n",cas,Zombie);
121     }
122     return 0;
123 }

猜你喜欢

转载自www.cnblogs.com/LocaEtric/p/9150894.html