1. 程式人生 > 其它 >P2482 [SDOI2010] 豬國殺

P2482 [SDOI2010] 豬國殺

著名題目(
寫+調大概一晚上+一上午

(可能)難以理解的題意:

  • 主豬身份公開
  • 南豬入侵、萬箭齊發只轉一圈(對每個人結算一次)
  • 如果 A 無懈了 B 對 C 發起的南豬入侵、萬箭齊發、決鬥,那麼 A 對 C 獻殷勤
  • 如果之後有 D 無懈了 A 的無懈可擊,那麼 D 對 A 表敵意;同樣,後面每個人無懈上一個人的無懈可擊時,都算且僅算作對上一個人表敵意
  • 南豬入侵、萬箭齊發結算到某個人時,先看是否有人使用無懈可擊(並且成功,也就是沒有被別的無懈無懈掉),再看是否能出殺或閃
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<assert.h>
#include<vector>
inline char getLetter(){
	char c=getchar();
	while(c<'A'||c>'Z') c=getchar();
	return c;
}
#define N 12
#define M 2006
#define HP_LIM 4
struct Pig{
	char type;
	int look,hp,mulKill;//look: 0=none 1=類反豬 2=已跳忠 3=已跳反 4=已死
	std::vector<char>card;
	inline void init(){
		type=getLetter();getLetter();
		card.push_back(getLetter());card.push_back(getLetter());card.push_back(getLetter());card.push_back(getLetter());
		hp=HP_LIM;look=0;mulKill=0;
	}
};
int n,m,cntFP;
Pig p[N];
int nex[N];
char card[M];
int cardNow;
inline char getCard(){if(++cardNow>m) cardNow=m;return card[cardNow];}
inline void output(){
	puts(cntFP?"FP":"MP");
	for(int i=1;i<=n;i++){
		if(p[i].look==4) puts("DEAD");
		else{
			for(std::vector<char>::iterator now=p[i].card.begin();now!=p[i].card.end();now++) printf("%c ",*now);
			puts("");
		}
	}
}
inline void dead(int u,int v){//u killed v
	p[v].hp--;p[v].look=4;p[v].mulKill=0;std::vector<char>().swap(p[v].card);
	for(int i=1;i<=n;i++)if(nex[i]==v&&p[i].look!=4) nex[i]=nex[v];
	if(p[v].type=='M') output(),exit(0);
	else if(p[v].type=='F'){
		if(!--cntFP) output(),exit(0);
		p[u].card.push_back(getCard()),p[u].card.push_back(getCard()),p[u].card.push_back(getCard());
	}
	else if(p[v].type=='Z'&&p[u].type=='M') std::vector<char>().swap(p[u].card),p[u].mulKill=0;
}
inline void makeHostility(int u,int v){
	if(p[v].type=='M'||p[v].look==2) p[u].look=3;
	else if(p[v].look==3) p[u].look=2;
}
inline int canMakeHostility(int i,int j){
	return (p[i].type=='M'&&(p[j].look==1||p[j].look==3))||(p[i].type=='Z'&&p[j].look==3)||(p[i].type=='F'&&(p[j].type=='M'||p[j].look==2));
}
inline void makeGoodwill(int u,int v){
	if(p[v].type=='M'||p[v].look==2) p[u].look=2;
	else if(p[v].look==3) p[u].look=3;
}
inline int canMakeGoodwill(int u,int v){
	return ((p[u].type=='M'||p[u].type=='Z')&&(p[v].type=='M'||p[v].look==2))||(p[u].type=='F'&&p[v].look==3);
}
inline int use(int u,char c){
	for(std::vector<char>::iterator now=p[u].card.begin();now!=p[u].card.end();now++)
		if(*now==c) return p[u].card.erase(now),1;
	return 0;
}
inline void attack(int u,int v){
	if(p[v].hp<=1){
		if(use(v,'P')) return;
		dead(u,v);
	}
	else p[v].hp--;
}
inline int tryUseJ(int user,int target,int attitude){//嘗試使用無懈可擊使 user 使用的錦囊失效,attitude: 1=殷勤 2=敵意(對 target)
	int u=user;
	do{
		if(((attitude==1&&canMakeGoodwill(u,target))||(attitude==2&&canMakeHostility(u,target)))&&use(u,'J')){
			if(attitude==1) makeGoodwill(u,target);
			else if(attitude==2) makeHostility(u,target);
			return !tryUseJ(u,u,2);
		}
		u=nex[u];
	}while(u!=user);
	return 0;
}
inline void useKill(int u,int v){//u use kill to v
	makeHostility(u,v);
	if(use(v,'D')) return;
	attack(u,v);
}
inline void useDuel(int u,int v){//u use duel to v
	makeHostility(u,v);
	if(tryUseJ(u,v,1)) return;
	for(;;){
		if((p[u].type=='M'&&p[v].type=='Z')||!use(v,'K')) return attack(u,v),void();
		if((p[v].type=='M'&&p[u].type=='Z')||!use(u,'K')) return attack(v,u),void();
	}
}
inline void makeRound(int id){
	p[id].card.push_back(getCard());p[id].card.push_back(getCard());
	int usedKill=0;
START_ROUND:
	for(std::vector<char>::iterator now=p[id].card.begin();now!=p[id].card.end();now++){
		if(*now=='P'){
			if(p[id].hp==HP_LIM) continue;
			p[id].hp++;p[id].card.erase(now);
			goto START_ROUND;
		}
		else if(*now=='K'){
			if(usedKill&&!p[id].mulKill) continue;
			if(canMakeHostility(id,nex[id])){
				p[id].card.erase(now);usedKill=1;useKill(id,nex[id]);
				goto START_ROUND;
			}
		}
		else if(*now=='Z'){
			p[id].card.erase(now);p[id].mulKill=1;
			goto START_ROUND;
		}
		else if(*now=='F'){
			if(p[id].type=='F'){
				for(int j=nex[id];j!=id;j=nex[j])if(p[j].type=='M'){
					p[id].card.erase(now);useDuel(id,j);
					goto START_ROUND;
				}
			}
			for(int j=nex[id];j!=id;j=nex[j])if(canMakeHostility(id,j)){
				p[id].card.erase(now);useDuel(id,j);
				goto START_ROUND;
			}
		}
		else if(*now=='N'){
			p[id].card.erase(now);
			for(int j=nex[id];j!=id;j=nex[j]){
				if(tryUseJ(id,j,1)) continue;
				if(use(j,'K')) continue;
				attack(id,j);
				if(p[j].type=='M'&&!p[id].look) p[id].look=1;
			}
			goto START_ROUND;
		}
		else if(*now=='W'){
			p[id].card.erase(now);
			for(int j=nex[id];j!=id;j=nex[j]){
				if(tryUseJ(id,j,1)) continue;
				if(use(j,'D')) continue;
				attack(id,j);
				if(p[j].type=='M'&&!p[id].look) p[id].look=1;
			}
			goto START_ROUND;
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) p[i].init();
	for(int i=1;i<=m;i++) card[i]=getLetter();
	for(int i=1;i<=n;i++) cntFP+=(p[i].type=='F');
	for(int i=1;i<n;i++) nex[i]=i+1;nex[n]=1;
	for(int i=1;;i=nex[i]) makeRound(i);
	return 0;
}