[BZOJ 1972][Sdoi2010]猪国杀
1972: [Sdoi2010]猪国杀
Time Limit: 1 Sec Memory Limit: 64 MB
Submit: 364 Solved: 204
[Submit][Status][Discuss]Description
概述
《猪国杀》是一种多猪牌类回合制游戏,一共有三种角色:主猪,忠猪,反猪。每局游戏主猪有且只有一只,忠猪和反猪可以有多只,每只猪扮演一种角色。游戏目的主猪(MP):自己存活的情况下消灭所有的反猪。忠猪(ZP):不惜一切保护主猪,胜利条件与主猪相同。反猪(AP):杀死主猪。游戏过程游戏开始时候,每个玩家手里都会有 4 张牌,且体力上限和初始体力都是 4 。开始游戏时,从主猪开始,按照逆时针方向(数据中就是按照编号从 1, 2, 3...n, 1... 的顺序)依次行动。每个玩家自己的回合可以分为 4 个阶段摸牌阶段从牌堆顶部摸两张牌,依次放到手牌的最右边。出牌阶段你可以使用 0 张到任意张牌,每次使用牌的时候都使用最靠左的能够使用的牌。当然,要满足如下规则如果没有猪哥连弩,每个出牌阶段只能使用一次“杀”来攻击。任何牌被使用后被弃置(武器是装备上)。被弃置的牌以后都不能再用,即与游戏无关。各种牌介绍每张手牌用一个字母表示,字母代表牌的种类。基本牌『桃(P)』在自己的回合内,如果自己的体力值不等于体力上限,那么使用一个桃可以为自己补充一点体力;否则不能使用桃。桃只能对自己使用。在自己的回合外,如果自己的血变为 0 或者更低,那么也可以使用。『杀(K)』在自己的回合内,对攻击范围内除自己以外的一名角色使用。如果没有被『闪』抵消,则造成 1 点伤害。无论有无武器,杀的攻击范围都是 1。『闪(D)』当你受到杀的攻击时,可以弃置一张闪来抵消杀的效果。锦囊牌『决斗(F)』出牌阶段,对除自己以外任意一名角色使用,由目标角色先开始,自己和目标角色轮流弃置一张杀,首先没有杀可弃的一方受到1点伤害,另一方视为此伤害的来源。『南猪入侵(N)』出牌阶段,对除你以外所有角色使用,按逆时针顺序从使用者下家开始依次结算,除非弃置一张杀,否则受到1点伤害。『万箭齐发(W)』和南猪入侵类似,不过要弃置的不是杀而是闪。『无懈可击(J)』在目标锦囊生效前抵消其效果。每次有一张锦囊即将生效时,从使用这张锦囊的猪开始,按照逆时针顺序,依次得到使用无懈可击的机会。效果用于决斗时,决斗无效并弃置。用于南猪入侵或万箭齐发时,当结算到某个角色时才能使用,当前角色不需弃置牌并且不会受到伤害(仅对一个角色产生效果)。用于无懈可击时,成为目标的无懈可击被无效。装备牌『猪哥连弩(Z)』武器,攻击范围 1,出牌阶段你可以使用任意张杀。同一时刻最多只能装一个武器。如果先前已经有了一把武器,那么之后再装武器的话,会弃置以前的武器来装现在的武器。特殊事件及概念解释伤害来源杀、南猪入Input
第一行包含两个正整数n(2 <= n <= 10) 和m( m <= 2000),分别代表玩家数和牌堆中牌的数量。数据保证牌的数量够用。 接下来n行,每行5个字符串,依次表示对第i只猪的角色和初始4张手牌描述。编号为1的肯定是主猪。 再接下来一行,一共m个字符串,按照从牌堆顶部到牌堆底部的顺序描述每张牌。 所有的相邻的两个字符串都严格用1个空格隔开,行尾没有多余空格。
Output
输出数据第一行包含一个字符串代表游戏结果。如果是主猪胜利,那么输出“MP”,否则输出“FP”。数据保证游戏总会结束。 接下来n行,第i行是对第i只猪的手牌描述(注意只需要输出手牌),按照手牌从左往右的顺序输出,相邻两张牌用一个空格隔开,行末尾没有多余空格。如果这只猪已阵亡,那么只要输出“DEAD”即可。注意如果要输出手牌而没有手牌的话,那么只需输出一个空行。
Sample Input
3 10
MP D D F F
ZP N N N D
FP J J J J
F F D D J J F F K D
Sample Output
FP
DEAD
DEAD
J J J J J D
HINT
样例1说明:第一回合主猪没有目标可以表敌意;接下来忠猪使用了3张南猪入侵,主猪掉了3点体力,并认为该角色为类反猪,3号角色尽管手里有无懈可击,但是因为自己未表明身份,所以同样不能对自己用,乖乖掉3点体力;下一回合反猪无牌可出;接下来主猪对着类反猪爆发,使用4张决斗,忠猪死亡,结果主猪弃掉所有牌;下来反猪摸到一张杀直接杀死主猪获胜。 数据说明:一共20组测试数据,每个点5分。10%的数据没有锦囊牌,另外20%的数据没有无懈可击。
Source
麻麻我要把这个出题人挂起来裱QAQ!
题解
不想多说啥, 就是个大模拟(难以置信的是这是个省选题?!)
说一下我碰到的几个辣鸡坑爹细节好了
1.抽完牌要强行接着抽最后一张
2.清空主公的牌的时候, 首先注意连弩标记也要重置, 其次还得注意牌面迭代器QAQ(2个点RE到死...)
3.无懈可击在AOE下只对一人有效, 不能解决掉整个锦囊
4.无懈可击的遍历判定只有第一个打出无懈可击的玩家有无懈可击的权利, 如果这张无懈可击被后续的无懈可击无效掉也不会继续给后面的玩家机会
5.BZOJ辣鸡题面只截了一半吃枣药丸...可读题面
6.反贼的所有决斗无条件扔给主公
7.杀/决斗/无懈可击都是跳身份的标志, 而且只能对显露身份的玩家使用
然后就是自己的思博错误: 南蛮入侵和万箭齐发的时候如果被无懈可击掉的话判定点不会继续迭代而会消耗掉所有无懈可击QAQ
参考代码
1 #include <list> 2 #include <vector> 3 #include <cstdio> 4 #include <cstring> 5 #include <iostream> 6 #include <algorithm> 7 8 struct Card; 9 10 struct Pig{ 11 Pig(int); 12 int ID; 13 int HP; 14 bool LN; 15 bool JMP,APL; 16 bool MP,AP,ZP; 17 Pig* prev; 18 Pig* next; 19 void Jump(); 20 void Clear(); 21 void Round(); 22 void Print(); 23 void Arrows(); 24 void SetAPL(); 25 void Die(Pig*); 26 void Invasion(); 27 void GetCard(int); 28 void GetHurt(Pig*); 29 bool Kill(); 30 bool TryDuel(); 31 bool UseKill(); 32 bool UseMiss(); 33 bool UsePeach(); 34 bool JFor(bool); 35 bool Duel(Pig*); 36 bool UseCard(char); 37 bool FindJBecauseOf(Pig*); 38 std::list<Card*> cards; 39 }; 40 41 struct Card{ 42 Card(); 43 char type; 44 bool Act(Pig*); 45 }; 46 47 int n; 48 int m; 49 int APs; 50 bool END; 51 char last; 52 char buf[5]; 53 std::vector<Pig*> v; 54 55 void Initialize(); 56 57 int main(){ 58 Initialize(); 59 Pig* root=v[0]; 60 while(!END){ 61 root->Round(); 62 root=root->next; 63 } 64 if(APs==0) 65 puts("MP"); 66 else 67 puts("FP"); 68 for(std::vector<Pig*>::iterator i=v.begin();i!=v.end();++i) 69 (*i)->Print(); 70 return 0; 71 } 72 73 bool Pig::Kill(){ 74 if(this->AP){ 75 if(this->next==v[0]||(this->next->ZP&&this->next->JMP)){ 76 this->JMP=true; 77 if(!this->next->UseMiss()) 78 this->next->GetHurt(this); 79 return true; 80 } 81 } 82 else if(this->MP){ 83 if(this->next->JMP){ 84 if(this->next->AP){ 85 if(!this->next->UseMiss()) 86 this->next->GetHurt(this); 87 return true; 88 } 89 } 90 else{ 91 if(this->next->APL){ 92 if(!this->next->UseMiss()) 93 this->next->GetHurt(this); 94 return true; 95 } 96 } 97 } 98 else if(this->ZP){ 99 if(this->next->AP&&this->next->JMP){ 100 if(!this->next->UseMiss()) 101 this->next->GetHurt(this); 102 return true; 103 } 104 } 105 return false; 106 } 107 108 bool Pig::TryDuel(){ 109 if(this->AP){ 110 this->JMP=true; 111 if(!v[0]->FindJBecauseOf(this)){ 112 if(v[0]->Duel(this)) 113 v[0]->GetHurt(this); 114 else 115 this->GetHurt(v[0]); 116 } 117 return true; 118 } 119 else if(this->MP){ 120 Pig* root=this->next; 121 while(root!=this){ 122 if((root->AP&&root->JMP)||(root->APL&&!root->JMP)){ 123 if(!root->FindJBecauseOf(this)){ 124 if(root->Duel(this)) 125 root->GetHurt(this); 126 else 127 this->GetHurt(root); 128 } 129 return true; 130 } 131 root=root->next; 132 } 133 } 134 else if(this->ZP){ 135 Pig* root=this->next; 136 while(root!=this){ 137 if(root->AP&&root->JMP){ 138 this->JMP=true; 139 if(!root->FindJBecauseOf(this)){ 140 if(root->Duel(this)) 141 root->GetHurt(this); 142 else 143 this->GetHurt(root); 144 } 145 return true; 146 } 147 root=root->next; 148 } 149 } 150 return 0; 151 } 152 153 bool Pig::Duel(Pig* source){ 154 if(this->ZP&&source->MP) 155 return true; 156 else{ 157 while(true){ 158 if(!this->UseKill()) 159 return true; 160 if(!source->UseKill()) 161 return false; 162 } 163 } 164 } 165 166 void Pig::Round(){ 167 this->GetCard(2); 168 bool Kused=false; 169 bool flag=false; 170 for(std::list<Card*>::iterator i=this->cards.begin();(!this->cards.empty())&&i!=this->cards.end();flag?i:++i){ 171 flag=false; 172 if(END||this->HP==0) 173 break; 174 if((*i)->type=='P'&&this->HP<4){ 175 this->HP++; 176 if(!this->cards.empty()) 177 this->cards.erase(i); 178 i=this->cards.begin(); 179 flag=true; 180 } 181 else if((*i)->type=='N'){ 182 this->Invasion(); 183 if(!this->cards.empty()) 184 this->cards.erase(i); 185 i=this->cards.begin(); 186 flag=true; 187 } 188 else if((*i)->type=='W'){ 189 this->Arrows(); 190 if(!this->cards.empty()) 191 this->cards.erase(i); 192 i=this->cards.begin(); 193 flag=true; 194 } 195 else if((*i)->type=='K'&&(!Kused||this->LN)){ 196 if(this->Kill()){ 197 if(!this->cards.empty()) 198 this->cards.erase(i); 199 i=this->cards.begin(); 200 flag=true; 201 Kused=true; 202 } 203 } 204 else if((*i)->type=='F'){ 205 if(this->TryDuel()){ 206 if(!this->cards.empty()) 207 this->cards.erase(i); 208 i=this->cards.begin(); 209 flag=true; 210 } 211 } 212 else if((*i)->type=='Z'){ 213 if(!this->cards.empty()) 214 this->cards.erase(i); 215 i=this->cards.begin(); 216 flag=true; 217 if(this->LN==false){ 218 this->LN=true; 219 } 220 } 221 } 222 } 223 224 bool Pig::JFor(bool AP){ 225 Pig* root=this; 226 do{ 227 if(root->AP==AP){ 228 if(root->UseCard('J')){ 229 root->JMP=true; 230 return !root->JFor(!AP); 231 } 232 } 233 root=root->next; 234 }while(root!=this); 235 return false; 236 } 237 238 bool Pig::FindJBecauseOf(Pig* source){ 239 if((!this->JMP)&&(!this->MP)) 240 return false; 241 else{ 242 return source->JFor(this->AP); 243 } 244 } 245 246 void Pig::GetHurt(Pig* source){ 247 this->HP--; 248 if(this->HP<=0){ 249 if(this->UsePeach()) 250 this->HP++; 251 else 252 this->Die(source); 253 } 254 } 255 256 void Pig::Clear(){ 257 this->LN=false; 258 this->cards.clear(); 259 } 260 261 void Pig::Die(Pig* source){ 262 this->prev->next=this->next; 263 this->next->prev=this->prev; 264 if(this->MP) 265 END=true; 266 else if(this->AP){ 267 APs--; 268 if(APs<=0){ 269 END=true; 270 return; 271 } 272 source->GetCard(3); 273 } 274 else if(this->ZP&&source->MP){ 275 source->Clear(); 276 } 277 } 278 279 bool Pig::UseKill(){ 280 return this->UseCard('K'); 281 } 282 283 bool Pig::UseMiss(){ 284 return this->UseCard('D'); 285 } 286 287 bool Pig::UsePeach(){ 288 return this->UseCard('P'); 289 } 290 291 void Pig::SetAPL(){ 292 if(!this->JMP) 293 this->APL=true; 294 } 295 296 bool Pig::UseCard(char ch){ 297 for(std::list<Card*>::iterator i=this->cards.begin();i!=this->cards.end();++i){ 298 if((*i)->type==ch){ 299 this->cards.erase(i); 300 return true; 301 } 302 } 303 return false; 304 } 305 306 void Initialize(){ 307 scanf("%d%d",&n,&m); 308 m+=4*n; 309 for(int i=0;i<n;i++) 310 v.push_back(new Pig(i)); 311 v[n-1]->next=v[0]; 312 v[0]->prev=v[n-1]; 313 for(int i=1;i<n;i++){ 314 v[i-1]->next=v[i]; 315 v[i]->prev=v[i-1]; 316 } 317 if(APs==0) 318 END=true; 319 } 320 321 Pig::Pig(int ID){ 322 this->ID=ID; 323 this->LN=false; 324 this->JMP=this->APL=false; 325 this->AP=this->ZP=this->MP=false; 326 this->HP=4; 327 scanf("%s",buf); 328 if(*buf=='M') 329 this->MP=true; 330 else if(*buf=='Z') 331 this->ZP=true; 332 else 333 this->AP=true; 334 this->GetCard(4); 335 if(this->AP) 336 APs++; 337 } 338 339 Card::Card(){ 340 if(m>0){ 341 scanf("%s",buf); 342 this->type=*buf; 343 last=this->type; 344 m--; 345 } 346 else 347 this->type=last; 348 } 349 350 void Pig::Arrows(){ 351 Pig* root=this->next; 352 while(root!=this){ 353 if(root->FindJBecauseOf(this)){ 354 root=root->next;// QAQ 355 continue; 356 } 357 if(!root->UseMiss()){ 358 if(root->MP) 359 this->SetAPL(); 360 root->GetHurt(this); 361 } 362 if(END) 363 return; 364 root=root->next; 365 } 366 } 367 368 void Pig::Invasion(){ 369 Pig* root=this->next; 370 while(root!=this){ 371 if(root->FindJBecauseOf(this)){ 372 root=root->next;// QAQ 373 continue; 374 } 375 if(!root->UseKill()){ 376 if(root->MP) 377 this->SetAPL(); 378 root->GetHurt(this); 379 } 380 if(END) 381 return; 382 root=root->next; 383 } 384 } 385 386 void Pig::GetCard(int cnt){ 387 while(cnt--) 388 this->cards.push_back(new Card()); 389 } 390 391 void Pig::Print(){ 392 if(this->HP<=0) 393 puts("DEAD"); 394 else{ 395 while(!this->cards.empty()){ 396 putchar(this->cards.front()->type); 397 this->cards.pop_front(); 398 if(!this->cards.empty()) 399 putchar(' '); 400 } 401 putchar('\n'); 402 } 403 }
(补图了补图了)
本博客已弃用, 新个人主页: https://rvalue.moe, 新博客: https://blog.rvalue.moe