【BZOJ1972】[SDOI2010] 猪国杀(恶心的大模拟)
大致题意: 让你模拟一个游戏猪国杀的过程。
几大坑点
对于这种模拟题,具体思路就不讲了,就说说有哪些坑点。
题面有锅,反猪是\(FP\)。
数据有锅,牌堆中的牌可能不够用,牌堆为空之后需一直抽最后一张牌。
主猪杀死忠猪后猪哥连弩也要清除。
无懈可击也可以用无懈可击抵消。
使用决斗的猪可能死亡。
无懈可击是从使用锦囊牌的猪开始轮流选择是否响应。
使用完一张牌后(不包括桃)有可能会导致之前跳过的杀或决斗有对象使用,因此要重新扫描一遍。
只有主猪会特别针对类反猪。
如果杀死某只反猪后游戏结束,是不摸三张牌的。
大致就是这些了,我还犯了一些其他十分智障的错误,以至于调到绝望。
代码
#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define uint unsigned int
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define abs(x) ((x)<0?-(x):(x))
#define INF 1e9
#define Inc(x,y) ((x+=(y))>=MOD&&(x-=MOD))
#define ten(x) (((x)<<3)+((x)<<1))
#define hl_AK_NOI true
#define GetCard(x) (s[x].card[++s[x].k]=cards[cd<m?++cd:m])//摸一张牌,注意牌堆中的牌可能不够用
using namespace std;
int n,m,cd=0,Last[15],Next[15];
char cards[2005];
class FIO
{
private:
#define Fsize 100000
#define tc() (FinNow==FinEnd&&(FinEnd=(FinNow=Fin)+fread(Fin,1,Fsize,stdin),FinNow==FinEnd)?EOF:*FinNow++)
#define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,FoutSize,stdout),Fout[(FoutSize=0)++]=ch))
int f,FoutSize,OutputTop;char ch,Fin[Fsize],*FinNow,*FinEnd,Fout[Fsize],OutputStack[Fsize];
public:
FIO() {FinNow=FinEnd=Fin;}
inline void read(int &x) {x=0,f=1;while(!isdigit(ch=tc())) f=ch^'-'?1:-1;while(x=ten(x)+(ch&15),isdigit(ch=tc()));x*=f;}
inline void read_char(char &x) {while(isspace(x=tc()));}
inline void read_string(string &x) {x="";while(isspace(ch=tc()));while(x+=ch,!isspace(ch=tc())) if(!~ch) return;}
inline void write(int x) {if(!x) return (void)pc('0');if(x<0) pc('-'),x=-x;while(x) OutputStack[++OutputTop]=x%10+48,x/=10;while(OutputTop) pc(OutputStack[OutputTop]),--OutputTop;}
inline void write_char(char x) {pc(x);}
inline void write_string(string x) {register int i,len=x.length();for(i=0;i<len;++i) pc(x[i]);}
inline void end() {fwrite(Fout,1,FoutSize,stdout);}
}F;
struct Pig//定义结构体,表示一只猪
{
int id,Type,hp,status,k;//id记录猪的编号,Type记录猪的类型,hp记录猪的剩余血量,status记录猪当前表明的状态(0:未知;1:主猪;2:忠猪;3:反猪;4:类反猪),k记录手中牌的数量
char card[5005];//card存储手牌
bool dead,Z;//dead记录猪是否死亡,Z记录猪是否有猪哥连弩
Pig(int x=0,string y="NULL"):id(x),Type(y[0]^'M'?(y[0]^'F'?2:3):1)//构造函数
{
if(y=="NULL") return;//一开始很智障地没写这句话,结果炸飞
status=(Type==1),hp=k=4,dead=Z=false;
register int i;
for(i=1;i<=4;++i) F.read_char(card[i]);//读入手牌
for(i=5;i<=5000;++i) card[i]='\0';
}
inline void Hurt(int);//受到伤害
inline bool Use(char ch)//查询是否有这张牌,如果有就使用并返回true,否则返回false
{
for(register int i=1;i<=k;++i) if(card[i]==ch) return card[i]='\0',true;//扫描每一张牌,查询是否有这张牌
return false;//返回false
}
}s[15];
inline void End()//游戏结束
{
register int i,j;
for(F.write_string(s[1].dead?"FP\n":"MP\n"),i=1;i<=n;++i)
{
if(s[i].dead) {F.write_string("DEAD\n");continue;}//如果死亡输出DEAD
for(j=1;j<=s[i].k;++j) if(s[i].card[j]) F.write_char(s[i].card[j]),F.write_char(' ');//输出手牌
F.write_char('\n');
}
F.end(),exit(0);
}
inline int GetLast(int x) {return s[Last[x]].dead?Last[x]=GetLast(Last[x]):Last[x];}//查询前一头猪
inline int GetNext(int x) {return s[Next[x]].dead?Next[x]=GetNext(Next[x]):Next[x];}//查询后一头猪
inline void Pig::Hurt(int x)//受到来源于编号为x的猪的一点伤害
{
if(--hp) return;//如果没死,退出函数
if(Use('P')) return (void)(++hp);//如果有桃,回一点体力
k=0,dead=true;//清空手牌,标记已死亡
if(Type==1) End();//如果死掉的是主猪,说明游戏结束了
if(Type==2&&s[x].Type==1) s[x].k=0,s[x].Z=false;//如果是主猪杀死了忠猪,清空主猪手牌,并注意清除猪哥连弩
Last[GetNext(id)]=Last[id],Next[GetLast(id)]=Next[id];//将该猪从牌局中删去
if(Type^3) return;//如果死的不是反猪,退出函数
register int i,t,FP=0;
for(i=1,t=0;i^t;i=GetNext(i),t=1) if(s[i].Type==3) {FP=true;break;}//判断是否还有反猪
if(!FP) End();//如果没有反猪,说明游戏结束了
GetCard(x),GetCard(x),GetCard(x);//摸三张牌
}
inline int GetStatus(int x,int y)//判断x与y的关系(1:同伙;2:没有关系;3:敌人)
{
if(!s[y].status) return 2;//如果y还没表明身份,返回2
switch(s[x].Type)//分类讨论(注意除主猪外其他猪与类反猪没有关系)
{
case 1:if(s[y].status==1) return 1;if(s[y].status==2) return 1;if(s[y].status==3) return 3;if(s[y].status==4) return 3;break;
case 2:if(s[y].status==1) return 1;if(s[y].status==2) return 1;if(s[y].status==3) return 3;if(s[y].status==4) return 2;break;
case 3:if(s[y].status==1) return 3;if(s[y].status==2) return 3;if(s[y].status==3) return 1;if(s[y].status==4) return 2;break;
}
return 2;
}
inline void BeGood(int x,int y)//通过x向y献殷勤,更新x的身份
{
if((s[y].status==1||s[y].status==2)&&s[x].Type^1) s[x].status=2;//如果y是忠猪或反猪且x不是主猪,说明x是忠猪
if(s[y].status==3) s[x].status=3;//如果y是反猪,说明x是反猪
}
inline void BeBad(int x,int y)//通过x向y表敌意,更新x的身份
{
if(s[y].status==1||s[y].status==2) s[x].status=3;//如果y是忠猪或反猪,说明x是反猪
if(s[y].status==3&&s[x].Type^1) s[x].status=2;//如果y是反猪且x不是主猪,说明x是忠猪
}
inline void K(int x,int y)//x向y打出一张杀
{
BeBad(x,y);//x向y表敌意了
if(!s[y].Use('D')) s[y].Hurt(x);//如果y没有出闪,就受到来自x的一点伤害
}
inline bool J(int x,int y,int v)//依次决定对于由x对y打出的一张无懈可击是否相应,其中v表示出无懈可击是献殷勤还是表敌意(1:献殷勤;3:表敌意)
{
register int i,t;
for(i=x,t=0;i^t;i=GetNext(i),t=x)
{
if(GetStatus(i,y)^v) continue;//如果不是该关系,就跳过
if(s[i].Use('J'))//如果打出无懈可击
{
v^1?BeBad(i,y):BeGood(i,y);
return !J(i,y,4-v);//递归调用该函数
}
}
return false;//没有猪打出无懈可击
}
inline void Fight(int x,int y)//x向y打出决斗
{
register int i1=1,i2=1;
BeBad(x,y);//x向y表敌意
if(J(x,y,1)) return;//如果有猪打出无懈可击,退出函数
if(s[x].Type==1&&s[y].Type==2) return (void)(s[y].Hurt(x));//如果x为主猪,y为忠猪,则必定是y受到伤害
while(hl_AK_NOI)//两猪轮流出杀
{
if(!s[y].Use('K')) return (void)(s[y].Hurt(x));//如果y没杀了,受到来自x的一点伤害
if(!s[x].Use('K')) return (void)(s[x].Hurt(y));//如果x没杀了,受到来自y的一点伤害
}
}
inline void AOE(int x,char Need)//由x发起的一次范围攻击,Need表示需要打出的牌
{
register int i;
for(i=GetNext(x);i^x;i=GetNext(i))
{
if(J(x,i,1)||s[i].Use(Need)) continue;//如果有猪打出无懈可击,或该猪打出了需要打出的牌,跳过
if(s[i].Type==1&&!s[x].status) s[x].status=4;//如果受到伤害的是主猪,且打出范围攻击的猪未表明身份,则标记其为类反猪
s[i].Hurt(x);//当前猪受到来自x的一点伤害
}
}
inline void Work()//出牌
{
register int i,j,kk=0,did=0,used;register char op;static int nw=1;
for(GetCard(nw),GetCard(nw),i=1;i<=s[nw].k;++i)//摸两张牌
{
op=s[nw].card[i],s[nw].card[i]='\0';
switch(op)
{
case 'K':
if(did&&!s[nw].Z) {s[nw].card[++kk]='K';break;}//如果出过杀,且没有猪哥连弩,跳过
if(GetStatus(nw,GetNext(nw))==3) K(nw,GetNext(nw)),did=1,i=kk=0;//如果与下一头猪是敌对关系,则打出杀,并从头开始扫描
else s[nw].card[++kk]='K';
break;
case 'F':
if(s[nw].Type==3) {Fight(nw,1),i=kk=0;break;}//如果是反猪,则对主猪打出决斗,并从头开始扫描
for(used=0,j=GetNext(nw);j^nw;j=GetNext(j)) if(GetStatus(nw,j)==3) {Fight(nw,j),used=true,i=kk=0;break;}//找到一个敌对关系的猪,打出决斗,并标记已使用,然后从头开始扫描
!used&&(s[nw].card[++kk]='F');
break;
case 'D':s[nw].card[++kk]='D';break;
case 'J':s[nw].card[++kk]='J';break;
case 'N':AOE(nw,'K'),i=kk=0;break;//打出南猪入侵,并从头开始扫描
case 'W':AOE(nw,'D'),i=kk=0;break;//打出万箭齐发,并从头开始扫描
case 'P':if(s[nw].hp<4) ++s[nw].hp;else s[nw].card[++kk]='P';break;//如果未满血,回复一点体力
case 'Z':s[nw].Z=true,i=kk=0;break;//装备猪哥连弩,然后从头开始扫描
}
if(!s[nw].k) kk=0;
}
s[nw].k=kk,nw=GetNext(nw);
}
int main()
{
register int i;register string st;
for(F.read(n),F.read(m),i=1;i<=n;++i) F.read_string(st),s[i]=Pig(i,st),Last[i]=i-1,Next[i]=i+1;//读入每一头猪的信息,并初始化其前一头猪和后一头猪
for(Last[1]=n,Next[n]=1,i=1;i<=m;++i) F.read_char(cards[i]);//读入牌堆
while(hl_AK_NOI) Work();//一直操作
return F.end(),0;
}
【BZOJ1972】[SDOI2010] 猪国杀(恶心的大模拟)的更多相关文章
- Bzoj1972: [Sdoi2010]猪国杀 题解(大模拟+耐心+细心)
猪国杀 - 可读版本 https://mubu.com/doc/2707815814591da4 题目可真长,读题都要一个小时. 这道题很多人都说不可做,耗时间,代码量大,于是,本着不做死就不会死的精 ...
- BZOJ1972:[SDOI2010]猪国杀(模拟)
Description 太长就不贴过来了 Solution 这个题是真的不难写……唯一的难度就在于理解题意上面……感觉这就是个阅读理解题啊…… 而且你三国杀玩的越多可能就越难写因为你无法理解那些猪的思 ...
- BZOJ1972: [Sdoi2010]猪国杀
“此题注意样例少了个J,且牌堆可能用完牌,若牌用完则不停取最后一张”.——hzwer 然后直接模拟,认真读题,理清思路. #include<cstdio> #include<list ...
- Luogu2482 [SDOI2010]猪国杀 ---- 模拟
Luogu2482 [SDOI2010]猪国杀 题意 ...... https://www.luogu.org/problemnew/show/P2482 总结 首先说一下代码的构思: 首先确定了所有 ...
- [BZOJ 1972][Sdoi2010]猪国杀
1972: [Sdoi2010]猪国杀 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 364 Solved: 204[Submit][Status][D ...
- BZOJ1972:[SDOI2010]猪国杀
我对模拟的理解:https://www.cnblogs.com/AKMer/p/9064018.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem ...
- [洛谷P2482][SDOI2010]猪国杀
题目大意:猪国杀,又一道大模拟题 题解:模拟,对于一个没有玩过三国杀的人来说,一堆细节不知道,写的十分吃力 卡点:无数,不想说什么了,这告诉我要多玩游戏 C++ Code: #include < ...
- 洛谷P2482 [SDOI2010]猪国杀——题解
猪国杀,模拟题的一颗耀眼的明珠,成长大牛.锻炼码力必写题! 模拟题没什么思维难度.只要按部就班地去做就是.模拟简单在这,难也在这.因为题面巨长,条件巨多,忽疏一点都有可能全盘皆输.故推荐考试时碰见了, ...
- 洛谷 P2482 loj #2885 [SDOI2010]猪国杀 题解【模拟】【贪心】【搜索】
好玩的模拟题. 以后要经常写模拟题鸭 题目描述 游戏背景 <猪国杀>是一种多猪牌类回合制游戏,一共有\(3\)种角色:主猪,忠猪,反猪.每局游戏主猪有且只有\(1\)只,忠猪和反猪可以有多 ...
随机推荐
- smix到底是个啥?Perl的正则表达式匹配模式
最近在研究一个perl项目,临时学习了一下perl语法,强行看项目源码.因为总是见到各种正则表达式后面接smxi之类,虽然知道是匹配模式,但脑子里毫无概念.所以特地去学习了一下. 以上为背景. Per ...
- elasticsearch shard 和 replica
(1)index包含多个shard(2)每个shard都是一个最小工作单元,承载部分数据,lucene实例,完整的建立索引和处理请求的能力(3)增减节点时,shard会自动在nodes中负载均衡(4) ...
- 51nod1315(位运算)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1315 题意:中文题诶- 思路:位或(|)运算是二进制位有一个 ...
- 洛谷P3068 [USACO13JAN]派对邀请函Party Invitations
P3068 [USACO13JAN]派对邀请函Party Invitations 题目描述 Farmer John is throwing a party and wants to invite so ...
- DNS 网关 路由 交换机 网桥 协议 服务器 这些都是什么关系?
来源:知乎 服务器:为你提供服务的机器.相当于马路边上的各种店面.虽然理论上任何一户人家都能开店为你提供服务,但是因为各种硬件资源限制而不适合开店.比如:小区道路比较窄(宽带带宽比较窄).家里地方太小 ...
- 我的省选 Day -10
Day -10 今天的分数也许会比昨天更低.. 感觉2017年比远古时代的2007年的第一试难诶. 估个分数好了,我猜88分(为什么猜了一个这么吉利的数字??到时候出来没几分就啪啪啪打脸了) 和昨天一 ...
- Ubuntu 防火墙IP转发做NAT,内网集群共享网络(简单)
服务器架构: 系统: Ubuntu 16.04 x64 使用自带防火墙 UFW 操作: 在有公网的服务器上,进行防火墙基本操作开启自己所需业务的端口,并按下方设置启动NAT: 其他内网机器修改网关或者 ...
- spring data之JDBCTemplate学习笔记
一.spring 数据访问哲学 1.为避免持久化的逻辑分散在程序的各个组件中,数据访问的功能应到放到一个或多个专注于此的组件中,一般称之为数据访问对象(data access object,DAO). ...
- DHCP DHCPv6
为了给网络客户机自动分配IP地址以及生成所需的配置参数,IETF分别给IPV4和IPV6网络定义了相关的协议标准,即DHCP(RFC2131)和DHCPV6(RFC3315),以及扩充的选项标准.本文 ...
- Spring ThreadPoolTaskExecutor队列满的异常处理
<!-- 配置线程池 --> <bean id="threadPool" class="org.springframework.scheduling.c ...