P2482 [SDOI2010] 猪国杀 解题报告
打了三天过了
爽!!!!!
回合架构
循环+死亡判断+结束判断
摸牌
K F N W Z
无懈可击
无懈可击分为两类:无懈可击其他锦囊牌、无懈可击无懈可击。判断的差别在于前者可以同阵营造成伤害,后者只能不同阵营互掐
易错点
1.无懈可击应从出牌人本身开始询问。例如1号位放万箭,无懈从1号开始询问。但若3号位出无懈,想无懈此无懈应从3号位开始询问。
2.注意猪哥连弩不能到手就用(75pts)
3.有些细节的地方不要手滑
4.决斗忠猪不反抗主猪不算献殷勤
code
/*基本牌:桃 P 杀 K 闪 D
锦囊牌:决斗 F 南猪入侵 N 万箭齐发 W 无懈可击 J
装备牌:猪哥连弩 Z
自己造的:E empty 表示空牌
hostility 表敌意:对某个角色使用杀、决斗;使用无懈可击抵消献殷勤;
complaisance 献殷勤:使用无懈可击挡下南猪入侵、万箭齐发、决斗;使用无懈可击抵消表敌意;
跳忠:通过行动表示自己是忠猪。对主猪或对某只已经跳忠的猪献殷勤,或者对某只已经跳反的猪表敌意;
跳反:通过行动表示自己是反猪。对主猪或对某只已经跳忠的猪表敌意,或者对某只已经跳反的猪献殷勤。
忠猪不会跳反,反猪也不会跳忠;不管是忠猪还是反猪,能够跳必然跳。
*/
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
#define pii pair<int,int>
const int maxn=12,maxm=1e5+10;
int n,m;
int fz_tot;//反猪数量
int ed=0;//2反贼赢 1忠猪赢
double t;
struct IDcard{
int id;//编号顺序
int nxt,pre;//前后 双向链表维护
string cst;//身份成分constituent
char card[maxm];//牌堆
int card_tot;//牌数
bool zgln;//是否配备猪哥连弩
int hp;//血量
bool die;//是否死掉
bool jump;//是否跳(反/忠)
bool sim;//是否是类反猪
}pig[maxn];
queue<char>card_heap;
void init(){
cin>>n>>m;
for(int i=1;i<=n;++i){
cin>>pig[i].cst;
if(pig[i].cst=="FP")fz_tot++;
pig[i].card_tot=0;
pig[i].id=i;
pig[i].hp=4;
pig[i].zgln=0;
pig[i].nxt=i+1;
pig[i].pre=i-1;
pig[i].sim=0;
pig[i].jump=0;
pig[i].die=0;
for(int j=1;j<=4;++j)
cin>>pig[i].card[++pig[i].card_tot];
}
pig[1].pre=n;
pig[n].nxt=1;
for(int i=1;i<=m;++i){
char pai;
cin>>pai;
card_heap.push(pai);
}
pig[1].jump=1;
}
void get_card(int x){
if(card_heap.size()==1)card_heap.push(card_heap.front());
pig[x].card[++pig[x].card_tot]=card_heap.front();
card_heap.pop();
}
void js(int x,int s){//x hp<=0时,s伤害来源
for(int i=1;i<=pig[x].card_tot;++i){
if(pig[x].card[i]=='P'){
pig[x].hp++;
pig[x].card[i]='E';
}
if(pig[x].hp>=1)return ;
}
pig[x].die=1;
int nxt=pig[x].nxt;
int pre=pig[x].pre;
pig[pre].nxt=nxt;
pig[nxt].pre=pre;
if(pig[x].cst=="FP")fz_tot--;
if(pig[x].cst=="MP"){ed=2;return ;}
if(!fz_tot){ed=1;return ;}
if(pig[x].cst=="FP")get_card(s),get_card(s),get_card(s);
if(pig[x].cst=="ZP"&&pig[s].cst=="MP"){
pig[s].zgln=0;
pig[s].card_tot=0;
}
}
void use_K(int u,int v){//u 对 v 使用 K
//表敌意
if(pig[v].cst=="MP")pig[u].jump=1,pig[u].sim=0;
if(pig[v].jump)pig[u].jump=1,pig[u].sim=0;
for(int i=1;i<=pig[v].card_tot;++i){
if(pig[v].card[i]=='D'){
pig[v].card[i]='E';
return ;
}
}
pig[v].hp--;
if(pig[v].hp<=0)js(v,u);
}
bool wxkj(int x1,int x2,int op){//x1对x2出牌 x2寻求同伴(自己)无懈 有/无 1/0
int i=x1;
while(1){
if(op==1){//帮x2出无懈可击 上一张是其他锦囊牌(可能对队友造成伤害)//没有亮明 队友(自己)不无懈
if(pig[x2].jump||x2==1)if((pig[i].cst=="FP"&&pig[x2].cst=="FP")||((pig[i].cst=="MP"||pig[i].cst=="ZP")&&(pig[x2].cst=="ZP"||x2==1))){
for(int j=1;j<=pig[i].card_tot;++j){
if(pig[i].card[j]=='J'){
pig[i].card[j]='E';
if(pig[x2].jump||x2==1)pig[i].jump=1,pig[i].sim=0;
return !wxkj(i,x1,0);
}
}
}
}else {//上一轮除了无懈可击 不让上一轮i,这一轮X1得逞 算是献殷勤,一定可以发牌 x1已暴露身份
if((pig[i].cst=="MP"||pig[i].cst=="ZP")&&pig[x1].cst=="FP"||(pig[x1].cst=="MP"||pig[x1].cst=="ZP")&&pig[i].cst=="FP"){
for(int j=1;j<=pig[i].card_tot;++j){
if(pig[i].card[j]=='J'){
pig[i].card[j]='E';
if(pig[x1].jump||x1==1)pig[i].jump=1,pig[i].sim=0;
return !wxkj(i,x1,0);
}
}
}
}
i=pig[i].nxt;
if(i==x1)break;
}
return 0;
}
void jd(int x1,int x2){//x1对x2决斗
if(wxkj(x1,x2,1))return ;//被无懈了
if(pig[x2].cst=="ZP"&&x1==1){
pig[x2].hp--;
if(!pig[x2].hp)js(x2,1);
return ;
}
int i=1,j=1;
pig[x2].card[pig[x2].card_tot+1]='E';//防止脏数据
pig[x1].card[pig[x1].card_tot+1]='E';
while(1){
while(pig[x2].card[j]!='K'&&j<=pig[x2].card_tot)j++;
if(j>pig[x2].card_tot){
pig[x2].hp--;
if(pig[x2].hp<=0)js(x2,x1);
return ;
}else {
pig[x2].card[j]='E';
}
while(pig[x1].card[i]!='K'&&i<=pig[x1].card_tot)i++;
if(i>pig[x1].card_tot){
pig[x1].hp--;
if(pig[x1].hp<=0)js(x1,x2);
return ;
}else {
pig[x1].card[i]='E';
}
}
}
void nzrq(int x1){//此处无懈可击仅对 1 个角色产生效果
for(int x2=pig[x1].nxt;x2!=x1;x2=pig[x2].nxt){
bool flg=0;
if(wxkj(x1,x2,1))continue;
for(int i=1;i<=pig[x2].card_tot;++i){
if(pig[x2].card[i]=='K'){
pig[x2].card[i]='E';
flg=1;
break ;
}
}
if(flg)continue;
pig[x2].hp--;
if(x2==1&&pig[x1].jump==0)pig[x1].sim=1;//造成伤害,类反
if(pig[x2].hp<=0)js(x2,x1);
if(ed)return ;
}
}
void wjqf(int x1){//此处无懈可击仅对 1 个角色产生效果
for(int x2=pig[x1].nxt;x2!=x1;x2=pig[x2].nxt){
bool flg=0;
if(wxkj(x1,x2,1))continue;
for(int i=1;i<=pig[x2].card_tot;++i){
if(pig[x2].card[i]=='D'){
pig[x2].card[i]='E';
flg=1;
break;
}
}
if(flg)continue;
pig[x2].hp--;
if(x2==1&&pig[x1].jump==0)pig[x1].sim=1;
if(pig[x2].hp<=0)js(x2,x1);
if(ed)return ;
}
}
void debug(){
for(int i=1;i<=n;++i)
for(int j=1;j<=pig[i].card_tot;++j)cout<<pig[i].card[j]<<" \n"[j==pig[i].card_tot];
cout<<"\n";
}
void Ett(){
int x=1;//当前回合决策猪
if(!fz_tot)ed=1;
while(!ed){
get_card(x);get_card(x);//回合摸牌阶段
// debug();
// for(int i=1;i<=3;++i)cout<<pig[i].hp<<" \n"[i==3];
int K_cnt=0;
for(int i=1;i<=pig[x].card_tot;++i){
if(ed)return ;
if(pig[x].die)break;
if(pig[x].card[i]=='E'||pig[x].card[i]=='J'||pig[x].card[i]=='D')continue;
if(pig[x].card[i]=='P'){
if(pig[x].hp!=4){
pig[x].hp++;
pig[x].card[i]='E';
}
continue;
}
if(pig[x].card[i]=='K'){
if(K_cnt<1||pig[x].zgln){
int target=pig[x].nxt;
if((pig[x].cst=="MP"&&((pig[target].jump&&pig[target].cst=="FP"))||(pig[target].sim&&pig[target].jump==0))){
pig[x].card[i]='E';
pig[x].sim=0;
use_K(x,target);
K_cnt++;
}
if(pig[x].cst=="FP"&&((pig[target].jump&&pig[target].cst=="ZP")||pig[target].cst=="MP")){
pig[x].jump=1;
pig[x].sim=0;
pig[x].card[i]='E';
use_K(x,target);
K_cnt++;
}
if(pig[x].cst=="ZP"&&pig[target].jump&&pig[target].cst=="FP"){
pig[x].jump=1;
pig[x].sim=0;
pig[x].card[i]='E';
use_K(x,target);
K_cnt++;
}
}
if(ed)return ;
continue;
}
if(pig[x].card[i]=='F'){//duel
if(pig[x].cst=="FP"){//have the chance of juedou MP!!
pig[x].jump=1;//跳反
pig[x].sim=0;
pig[x].card[i]='E';
jd(x,1);
i=0;//发牌后可能激活前面的牌
if(ed)return ;
continue;
}
else{
int bdy=pig[x].nxt;
while(bdy!=x){
if( (pig[x].cst=="MP"&&((pig[bdy].jump&&pig[bdy].cst=="FP")||(pig[bdy].sim&&pig[bdy].jump==0)))
|| (pig[x].cst=="ZP"&&pig[bdy].jump&&pig[bdy].cst=="FP") )
{
pig[x].jump=1;//跳忠 (1没事)
pig[x].sim=0;
pig[x].card[i]='E';
jd(x,bdy);
i=0;//发牌后可能激活前面的牌
if(ed)return ;
break;
}
bdy=pig[bdy].nxt;
}
}
continue;
}
if(pig[x].card[i]=='N'){//South pig in=vade
pig[x].card[i]='E';
nzrq(x);
i=0;//发牌后可能激活前面的牌
if(ed)return ;
continue;
}
if(pig[x].card[i]=='W'){//Ten thousand arrows shot at once.
pig[x].card[i]='E';
wjqf(x);
i=0;//发牌后可能激活前面的牌
if(ed)return ;
continue;
}
if(pig[x].card[i]=='Z'){
pig[x].zgln=1;
pig[x].card[i]='E';
i=0;
}
}
x=pig[x].nxt;
// if((clock()-t)/CLOCKS_PER_SEC>1)break;
}
}
void Sa(){
if(ed==1)cout<<"MP\n";
else cout<<"FP\n";
for(int i=1;i<=n;++i){
if(pig[i].die)cout<<"DEAD\n";
else{
for(int j=1;j<=pig[i].card_tot;++j)if(pig[i].card[j]!='E')cout<<pig[i].card[j]<<" ";
cout<<"\n";
}
}
}
int main(){
// ios::sync_with_stdio(0),cin.tie(0);
t=clock();
init();
Ett();//Enter the turn
Sa();//settle accounts 清算
return 0;
}
/*
6 15
MP K W Z Z
FP J Z J K
ZP J W K D
ZP N P K P
ZP J P F J
ZP J Z K J
Z P D J D K W F F Z N J F F J
*/
//