• 并不对劲的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 zin{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('
    ');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('
    ');
        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;
    }
    
    一些感想

    终于可以肆无忌惮地玩梗了!

  • 相关阅读:
    oracle教程:PLSQL常用方法汇总
    CORBA_TAO的环境配置
    安装使用Sybase ASE 12.5
    Oracle数据库备份命令Exp/Imp
    30个非常流行的提示信息插件(jQuery Tooltip Plugin)
    Spring.NET学习笔记——目录(转)
    JavaScript trim函数大赏 (转)
    使用基于 Informix Dynamic Server 的 Server Studio JE
    接触 CORBA 内幕: IOR、GIOP 和 IIOP
    Oracle数据库SQL
  • 原文地址:https://www.cnblogs.com/xzyf/p/11276120.html
Copyright © 2020-2023  润新知