并不对劲的bzoj1972:loj2885:p2482[SDOI2010]猪国杀
题目大意
只能放链接了。
题目中有一点没说:并不是保证牌够用,而是在牌不够用时反复抽最后一张牌。
题解
发现玩家的数量比较少,所以可以不太在意时间够不够用。
考虑三件事:1.基本操作,如摸牌、出牌、玩家死亡、牌的效果;2.游戏流程;3.出牌对象。
摸牌、出牌:
发现对于“某玩家的牌”的操作是从左往右扫第一张可用的,然后删掉(出牌),或者往最右放两张(摸牌),这两个操作用链表很好维护。建议把“判断从玩家\(x\)手牌里有没有值为\(k\)的,如果能,就把最左的\(k\)删去”和“在玩家\(x\)手牌最右放两张牌”这两个操作写成两个函数。建议记\(a_i\)表示玩家\(i\)是否装武器。
玩家死亡:
用链表维护每个玩家前后存活的玩家。玩家死亡时,先判手里有没有P,如果有,把血量改为1并复活(因为所有能造成伤害的牌,都只能造成1的伤害,所以不会降到0以下);如果没有,该玩家死亡,如果该玩家是MP或最后一个FP,则游戏结束,否则是FP的话伤害来源摸3张牌,是ZP且伤害来源是MP的话MP的手牌链表清空且令\(a_1=0\)。
牌的效果:
\(x\)对\(y\)出K:\(x\)身份暴露,判断\(y\)是否有D,若有则无事发生,若没有则\(y\)血量减少,判断\(y\)是否死亡。
\(x\)出P:血量+1。
\(x\)出Z:令\(a_x=1\)。
\(x\)出J:\(x\)身份暴露,从\(x\)开始依次判断是否有玩家成功出J,若有,则J被抵消;若没有,\(x\)出的J生效。建议用递归函数实现。
\(x\)出N或W:从\(x\)右边的玩家开始依次判断每个玩家是否会受伤,对于每个玩家,从\(x\)开始依次判断是否有玩家出J,若有则该玩家无事发生,若没有则判断该玩家能不能出K或D,若能则该玩家无事发生,否则该玩家掉血、判断死亡。这两个AOE几乎一样,建议一块写。需要注意的是,自己的AOE打到表明身份的队友时,可能会自己对自己的AOE出J。
\(x\)对\(y\)出F:\(x\)身份暴露,判J,判是否\(x\)为MP且\(y\)为ZP。维护两个指针,分别表示当前考虑到\(x 、 y\)的第几张牌。轮流移动指针至下一个K,如果一方没有K,则该方掉血、判断死亡。
记当前玩家为\(x\),用链表维护每个玩家前后存活的玩家。如果有人死亡则更新死亡者前后的玩家的链表。对于\(x\)的回合,先摸两张牌,再从左往右扫,如果无牌可出则回合结束,否则出牌,然后重新判断是否有牌可出(因为F、AOE出完后可能会有玩家出J,暴露身份,可能导致\(x\)有的牌变得可出)。需要注意\(x\)的回合可能因为\(x\)死亡而中断(\(x\)出F使自己死亡),要记\(x\)该回合是否出过K。
K:对在自己右边相邻的,且已经表明身份,且是敌人的玩家。
F:MP对逆时针方向第一个表明身份的FP或类反猪;ZP对逆时针方向第一个表明身份的FP;FP只会对MP。
J:记\(f(x,y,z)\space z\in\{0,1\}\)表示上一张牌是\(x\)对\(y\)的\(z\)行为(\(z=1\)表示献殷勤,\(z=0\)表示表敌意),是否被抵消。若\(z=1\)且\(k\)认为\(x\)是敌人且\(k\)有J,则\(k\)出J,然后\(f(k,x,0)\)判断该J是否生效;若\(z=0\)且\(k\)认为\(y\)是友军且\(k\)有J,则\(k\)出J,然后\(f(k,y,1)\)判断该J是否生效。注意要在出牌瞬间更改出牌者的“表面身份”,不然会影响到别的玩家是否出J。
想完这些后,下一步就是写了。好像模拟的内容和题目描述稍有不同就会WA一大片……
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define viewcd(u,k) for(int k=nxt[u];k;k=nxt[k])
#define LL long long
#define maxn 17
#define maxm 2007
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
int numpg,numcd,cf,stp;
int h[maxn],w[maxn],p[maxn],n[maxn],fake[maxn],real[maxn];
int nxt[maxm<<1],pre[maxm<<1],cntcd,chg;
char c[maxm<<1],C[maxm],s[10];
void addcd(int x,int k)
{
rep(i,1,k)
{
c[++cntcd]=C[numcd--];if(!numcd)numcd=1;
nxt[pre[x]]=cntcd,pre[cntcd]=pre[x],pre[x]=cntcd,nxt[cntcd]=x;
}
}//x gets k cards.
void del(int x,int k)
{
int nk=nxt[k],pk=pre[k];
pre[nk]=pk,nxt[pk]=nk;
}//x lose card k
void clear(){nxt[1]=pre[1]=1;w[1]=0;return;}//x lose its cards.
void kil(int x,int y)
{
if(real[y]==1&&x==1){clear();}
else if(real[y]==3){cf--;if(!cf)stp=1;if(!stp)addcd(x,3);}
else if(y==1)stp=1;
if(stp)return;
int ny=n[y],py=p[y];p[ny]=py,n[py]=ny;
}//x kill y.
int getcd(int x,char tp)
{
for(int k=nxt[x];k!=x;k=nxt[k])
if(tp==c[k]){del(x,k);return 1;}
return 0;
}//get card tp of x.
int reborn(int x){if(!getcd(x,'P'))return 0;h[x]=1;return 1;}//x is going to die.
int enemy(int x,int y){if(((fake[y]&1)&&fake[y]!=real[x])||(x==1&&fake[y]==2))return 1;return 0;}//x wants to kill y.
int nedJ(int x,int y,int f)
{
for(int k=n[x];k!=x;k=n[k])
{
if(!f&&fake[y]==real[k])
{
if(getcd(k,'J'))
{
fake[k]=real[k];
if(!nedJ(k,y,1))return 1;
}
}
if(f&&enemy(k,x))
{
if(getcd(k,'J'))
{
fake[k]=real[k];
if(!nedJ(k,x,0))return 1;
}
}
}
return 0;
}///x use ... on y
//0:enemy;1:friend
int prot(int x,int y)
{
if(fake[y]==real[x]){if(getcd(x,'J')){fake[x]=real[x];if(!nedJ(x,y,1))return 1;}}
for(int k=n[x];k!=x;k=n[k])if(fake[y]==real[k])
{
if(getcd(k,'J'))
{
fake[k]=real[k];
if(!nedJ(k,y,1))return 1;
}
}
return 0;
}//x use ... on y
void K(int x,int y)
{
fake[x]=real[x];
if(!getcd(y,'D')){h[y]--;if(h[y]==0&&!reborn(y))kil(x,y);}
}//
void F(int x,int y)
{
int kx=nxt[x],ky=nxt[y];
fake[x]=real[x];
if(prot(x,y))return;
if(real[y]!=1||x!=1)
{
while(ky!=y)
{
for(;ky!=y;ky=nxt[ky])if(c[ky]=='K')break;
if(c[ky]!='K')break;
del(y,ky),ky=nxt[ky],swap(x,y),swap(kx,ky);
}
}
if((real[y]==1&&x==1)||c[ky]!='K'){h[y]--;if(h[y]==0&&!reborn(y))kil(x,y);}
}//
void AOE(int x,char tp)//tp=='N':'K', tp=='W':'D'
{
char ned=(tp=='N')?'K':'D';
for(int y=n[x];y!=x;y=n[y])if(!prot(x,y))
{
if(!getcd(y,ned))
{
h[y]--;
if(!h[y]&&!reborn(y))kil(x,y);
if(stp)return;
if(y==1&&!fake[x])fake[x]=2;
}
}
}
int main()
{
numpg=read(),numcd=read();cntcd=numpg;
rep(i,1,numpg)
{
scanf("%s",s);pre[i]=nxt[i]=i;
real[i]=(s[0]=='M'||s[0]=='Z')?1:3;fake[i]=(i==1)?1:0;
rep(j,1,4)
{
scanf("%s",s);
c[++cntcd]=s[0];
nxt[pre[i]]=cntcd,pre[cntcd]=pre[i],pre[i]=cntcd,nxt[cntcd]=i;
}p[i]=(i-1)==0?numpg:i-1,n[i]=i==numpg?1:i+1,h[i]=4;
if(real[i]==3) cf++;
}
rep(i,1,numcd){scanf("%s",s);C[numcd-i+1]=s[0];}
if(cf==0)stp=1;
for(int x=1;!stp;x=n[x])
{
addcd(x,2);int mk=0,k;
usecd:
chg=0;
for(k=nxt[x];k!=x;k=nxt[k])
{
if(c[k]=='K'&&(!mk||w[x])&&enemy(x,n[x]))
{
mk=1;del(x,k),K(x,n[x]);chg=1;break;
}
else if(c[k]=='F')
{
int y;
if(real[x]==3){del(x,k),F(x,1);}
else
{
for(y=n[x];y!=x;y=n[y])if(enemy(x,y)){break;}
if(!enemy(x,y))continue;
del(x,k),F(x,y);
}
chg=1;break;
}
else if(c[k]=='N'||c[k]=='W'){del(x,k),AOE(x,c[k]);chg=1;break;}
else if(c[k]=='Z'){del(x,k),w[x]=1;chg=1;break;}
else if(c[k]=='P'&&h[x]<4){del(x,k),h[x]++;}
}
if(chg&&!stp&&h[x]){goto usecd;}
if(stp)break;
}
puts(h[1]>0?"MP":"FP");
rep(i,1,numpg)
{
if(h[i]<=0){printf("DEAD");}
else {for(int k=nxt[i];k!=i;k=nxt[k]){printf("%c ",c[k]);}}
puts("");
}
return 0;
}
一些感想
终于可以肆无忌惮地玩梗了!
并不对劲的bzoj1972:loj2885:p2482[SDOI2010]猪国杀的更多相关文章
- [洛谷P2482][SDOI2010]猪国杀
题目大意:猪国杀,又一道大模拟题 题解:模拟,对于一个没有玩过三国杀的人来说,一堆细节不知道,写的十分吃力 卡点:无数,不想说什么了,这告诉我要多玩游戏 C++ Code: #include < ...
- 洛谷P2482 [SDOI2010]猪国杀——题解
猪国杀,模拟题的一颗耀眼的明珠,成长大牛.锻炼码力必写题! 模拟题没什么思维难度.只要按部就班地去做就是.模拟简单在这,难也在这.因为题面巨长,条件巨多,忽疏一点都有可能全盘皆输.故推荐考试时碰见了, ...
- Luogu P2482 [SDOI2010]猪国杀
这道题在模拟界地位不亚于Luogu P4604 [WC2017]挑战在卡常界的地位了吧. 早上到机房开始写,中间因为有模拟赛一直到1点过才正式开始码. 一边膜拜CXR dalao一边写到3点左右,然后 ...
- 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 ...
- 洛谷 P2482 loj #2885 [SDOI2010]猪国杀 题解【模拟】【贪心】【搜索】
好玩的模拟题. 以后要经常写模拟题鸭 题目描述 游戏背景 <猪国杀>是一种多猪牌类回合制游戏,一共有\(3\)种角色:主猪,忠猪,反猪.每局游戏主猪有且只有\(1\)只,忠猪和反猪可以有多 ...
- BZOJ1972:[SDOI2010]猪国杀
我对模拟的理解:https://www.cnblogs.com/AKMer/p/9064018.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem ...
- 【BZOJ1972】[SDOI2010] 猪国杀(恶心的大模拟)
点此看题面 大致题意: 让你模拟一个游戏猪国杀的过程. 几大坑点 对于这种模拟题,具体思路就不讲了,就说说有哪些坑点. 题面有锅,反猪是\(FP\). 数据有锅,牌堆中的牌可能不够用,牌堆为空之后需一 ...
- Bzoj1972: [Sdoi2010]猪国杀 题解(大模拟+耐心+细心)
猪国杀 - 可读版本 https://mubu.com/doc/2707815814591da4 题目可真长,读题都要一个小时. 这道题很多人都说不可做,耗时间,代码量大,于是,本着不做死就不会死的精 ...
随机推荐
- Java后台开发精选知识图谱
1.引言: 学习一个新的技术时,其实不在于跟着某个教程敲出了几行.几百行代码,这样你最多只能知其然而不知其所以然,进步缓慢且深度有限,最重要的是一开始就对整个学习路线有宏观.简洁的认识,确定大的学习方 ...
- iOS学习之Autolayout
转载自:http://vit0.com/blog/2013/12/07/iosxue-xi-zhi-autolayout/ 学习资料 文章 Beginning Auto Layout Tutorial ...
- 微信公众号【黄小斜】和【Java技术江湖】
- 定时从linux获取信息放到windows上
环境:windows上代码路径下存放:WinSCP-5.13.8-Setup.exe 第一步:test.txt 拉取脚本的txt文本 解析:存放从linux路径下拉取所需源文件zyy_count. ...
- 15.反转链表 Java
题目描述 输入一个链表,反转链表后,输出新链表的表头. 思路 本题的关键就是在于对next域的赋值,同时对下一个节点进行保存,然后对把下一个节点赋给新的节点,这样依次循环完所有的节点.每次使新插入的节 ...
- IPv4 地址分类-for what
怎么分的:IPV4 地址分类 A B C D E 分来做什么:IP地址为什要分类?就是a类,b类,c类...? - wuxinliulei的回答 - 知乎
- 使用Git上传文件至Github
记录一下怎么把文件上传到Github,因为之前都存在本地,没上传过Github,自己以后看起来也有个记忆.因为我自己已经安装好Git和注册好Github账号了,设置好了SSH key.这部分不懂的,就 ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_5-03 feign结合hystrix断路器开发实战上
笔记 3.Feign结合Hystrix断路器开发实战<上> 简介:讲解SpringCloud整合断路器的使用,用户服务异常情况 1.加入依赖 注意:网上新旧版本问 ...
- dataset的find查找功能使用
var record = dataset.find(["status"],[curstatus]); //status指的是dataset中的某个字段,curstatus指的是指定 ...
- Spark在Windows上调试
1. 背景 (1) spark的一般开发与运行流程是在本地Idea或Eclipse中写好对应的spark代码,然后打包部署至驱动节点,然后运行spark-submit.然而,当运行时异常,如空指针或数 ...