[SDOI2010]猪国杀 题解
[SDOI2010]猪国杀 题解
Problem
见原题面
Solution
大模拟,前后共花了一天多一点写完,点几个需要注意的细节:
1.注意献殷勤和表敌意在出无懈可击时的差异,具体见代码
2.注意AOE伤害中途游戏结束不会继续结算这个AOE伤害
3.注意反猪有决斗的话必先对主猪使用
4.注意打出无懈可击的顺序,必须沿逆时针模拟
Code
#include<bits/stdc++.h>
using namespace std;
int n,m;
class Cards{
public:
char GetCard(){
return tot==m?P[m]:P[tot++];
}
bool IsCard(char c){
return c=='P'||c=='K'||c=='D'||c=='F'||c=='N'||c=='W'||c=='J'||c=='Z';
}
void Initialize(){
tot=1;
for(register int i=1;i<=m;++i){
char ch=getchar();
while(!IsCard(ch))
ch=getchar();
P[i]=ch;
}
}
private:
int tot;
char P[2005];
}H;
class Pig{
public:
int GetId(){
return Id;
}
int HPNow(){
return HP;
}
int CardNum(){
return C.size();
}
int Relation(int i){
return I[i-1];
}
char FindCard(int i){
return C[i];
}
bool IsDead(){
return Dead;
}
bool IsEquip(){
return Crossbow;
}
bool Have(char c){
for(register int i=0;i<C.size();++i){
if(C[i]==c)
return 1;
}
return 0;
}
bool IsCard(char c){
return c=='P'||c=='K'||c=='D'||c=='F'||c=='N'||c=='W'||c=='J'||c=='Z';
}
void Hurt(){
if(!--HP){
if(Have('P')){
HP=1;
Delt('P');
}
else
Dead=1;
}
}
void Equip(){
Crossbow=1;
}
void Print(){
for(register int i=0;i<C.size();++i){
putchar(C[i]);
putchar(' ');
}
}
void Discard(){
C.clear();
Crossbow=0;
}
void Recover(){
++HP;
}
void Delt(char c){
vector<char>::iterator IT;
for(IT=C.begin();IT!=C.end();++IT){
if(*IT==c){
C.erase(IT);
break;
}
}
}
void Getcards(int i){
while(i--)
C.push_back(H.GetCard());
}
void SetId(int i,int k){
I[i-1]=k;
}
void Initialize(int Now){
HP=4;Pos=Now;
char s[2];scanf("%s",s);
if(s[0]=='M')
Id=0;
if(s[0]=='F')
Id=-1;
if(s[0]=='Z')
Id=+1;
for(register int i=1;i<=4;++i){
char ch=getchar();
while(!IsCard(ch))
ch=getchar();
C.push_back(ch);
}
for(register int i=1;i<=n;++i)
I.push_back(0);
}
private:
int HP; //当前血量
int Id; //自身身份
int Pos; //自身位置
bool Dead; //是否死亡
bool Crossbow; //诸葛连弩
vector<int >I; //他人身份
vector<char>C; //当前手牌
}P[15];
int Find(int K,int T,int flag){
int Pos=0;
for(register int i=K;i<=n;++i){
if(Pos)
break;
if(!P[i].IsDead()&&((flag==1&&P[i].Relation(K)==-1)||(flag!=1&&P[i].Relation(T)==+1))&&P[i].Have('J')){
Pos=i;
break;
}
}
for(register int i=1;i< K;++i){
if(Pos)
break;
if(!P[i].IsDead()&&((flag==1&&P[i].Relation(K)==-1)||(flag!=1&&P[i].Relation(T)==+1))&&P[i].Have('J')){
Pos=i;
break;
}
}
return Pos;
}
void ResetId(int K,int T,int op){
for(register int i=1;i<=n;++i){
if(i==K)
P[i].SetId(i,1);
if(i!=K){
if(!P[i].Relation(K))
P[i].SetId(K,op*P[i].Relation(T));
if(!P[i].GetId()&&P[i].Relation(K)!=+1)
P[i].SetId(K,op*P[i].Relation(T));
}
}
return;
}
bool Offset(int From,int To,int flag){
int Able=1,Pos=Find(From,To,flag);
if(flag)
ResetId(From,To,-1);
flag=1;
while(Pos){
Able^=1;
ResetId(Pos,To,flag);
if(flag==-1)
To=From;
From=Pos;
P[Pos].Delt('J');
Pos=Find(From,To,flag);
if(Pos)
flag=P[Pos].Relation(To)==1?+1:-1;
}
return Able;
}
bool CheckOver(int flag){
int Num[3]={0,0,0};
for(register int i=1;i<=n;++i){
if(!P[i].IsDead())
++Num[P[i].GetId()+1];
}
if(!Num[0]){
if(flag)
printf("MP\n");
return 1;
}
if(!Num[1]){
if(flag)
printf("FP\n");
return 1;
}
return 0;
}
bool Kill(int K){
int T=K%n+1;
while(P[T].IsDead())
T=T%n+1;
if(P[K].Relation(T)!=-1)
return 0;
ResetId(K,T,-1);
if(P[T].Have('D'))
P[T].Delt('D');
else{
P[T].Hurt();
if(CheckOver(0))
return 1;
if(P[T].IsDead()){
if(P[T].GetId()==-1)
P[K].Getcards(3);
if(!P[K].GetId()&&P[T].GetId()==+1)
P[K].Discard();
}
}
return 1;
}
bool Duel(int K){
int T;
if(P[K].GetId()==-1){
for(register int i=1;i<=n;++i){
if(!P[i].GetId()){
T=i;
break;
}
}
}
else{
T=K%n+1;
while(P[T].IsDead()||P[K].Relation(T)!=-1){
T=T%n+1;
if(T==K)
break;
}
}
if(T==K)
return 0;
if(Offset(K,T,-1)){
if(!P[K].GetId()&&P[T].GetId()==+1){
P[T].Hurt();
if(P[T].IsDead())
P[K].Discard();
}
else{
int Now=T,Last=K;
while(P[Now].Have('K')){
P[Now].Delt('K');
swap(Now,Last);
}
P[Now].Hurt();
if(CheckOver(0))
return 1;
if(P[Now].IsDead()&&P[Now].GetId()==-1)
P[Last].Getcards(3);
}
}
return 1;
}
void AOE(int K,char c){
for(register int i=K+1;i<=n;++i){
if(P[i].IsDead())
continue;
if(Offset(K,i,0)){
if(P[i].Have(c))
P[i].Delt(c);
else{
if(!P[i].GetId()&&P[i].Relation(K)!=+1)
P[i].SetId(K,-1);
P[i].Hurt();
if(CheckOver(0))
break;
if(P[i].IsDead()){
if(!P[K].GetId()&&P[i].GetId()==+1)
P[K].Discard();
if(P[i].GetId()==-1)
P[K].Getcards(3);
}
}
}
}
if(CheckOver(0))
return;
for(register int i=0+1;i< K;++i){
if(P[i].IsDead())
continue;
if(Offset(K,i,0)){
if(P[i].Have(c))
P[i].Delt(c);
else{
if(!P[i].GetId()&&P[i].Relation(K)!=+1)
P[i].SetId(K,-1);
P[i].Hurt();
if(CheckOver(0))
break;
if(P[i].IsDead()){
if(!P[K].GetId()&&P[i].GetId()==+1)
P[K].Discard();
if(P[i].GetId()==-1)
P[K].Getcards(3);
}
}
}
}
return;
}
void Play(int K){
int Now=0,Flag=0;
P[K].Getcards(2);
while(!P[K].IsDead()){
if(Now>=P[K].CardNum())
break;
char c=P[K].FindCard(Now++);
if(c=='D')
continue;
if(c=='J')
continue;
if(c=='P'){
if(P[K].HPNow()<4){
Now=0;
P[K].Delt('P');
P[K].Recover();
}
}
if(c=='K'){
if(!Flag||P[K].IsEquip()){
if(Kill(K)){
Now=0;
Flag=1;
P[K].Delt('K');
}
}
}
if(c=='Z'){
Now=0;
P[K].Equip();
P[K].Delt('Z');
}
if(c=='F'){
if(Duel(K)){
Now=0;
P[K].Delt('F');
}
}
if(c=='W'){
Now=0;
AOE(K,'D');
P[K].Delt('W');
}
if(c=='N'){
Now=0;;
AOE(K,'K');
P[K].Delt('N');
}
if(CheckOver(0))
break;
}
return;
}
void work(){
while(true){
for(register int K=1;K<=n;++K){
if(P[K].IsDead())
continue;
Play(K);
if(CheckOver(0))
break;
}
if(CheckOver(1))
break;
}
for(register int i=1;i<=n;++i){
if(P[i].IsDead())
printf("DEAD\n");
else{
P[i].Print();
putchar('\n');
}
}
return;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
int main(){
n=read();m=read();
for(register int i=1;i<=n;++i)
P[i].Initialize(i);
int MP=0;
for(register int i=1;i<=n;++i){
if(!P[i].GetId())
MP=i;
}
for(register int i=1;i<=n;++i)
P[i].SetId(MP,P[i].GetId());
P[MP].SetId(MP,1);
H.Initialize();
work();
return 0;
}