专栏文章

题解:P5013 水の斗牛

P5013题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mincdngc
此快照首次捕获于
2025/12/02 00:06
3 个月前
此快照最后确认于
2025/12/02 00:06
3 个月前
查看原文
这个规则就不介绍了。自己看题。
这个我们可以按照每一个回合的顺序来模拟。
每一个回合分为如下几个部分。
  1. 发牌。
  2. 出牌。
  3. 比较和计分。
当然在模拟前,为了方便,我先写了一些结构体,并且重载运算符了这些结构体间的 >><<
  • 结构体 p,这个结构体用来存玩家的名字、计分、编号,和输入的顺序,因为作者太菜了,不会用 map,所以要排序后用二分。如果你选择用 map,你可以不管。
  • 结构体 poker,这个结构体里有两个 int,分别是一张牌的花色和点数。poker 之间比较非常明显,先比较点数,相同则比较花色。
  • 结构体 _player,记录了一个玩家的编号、手牌和出牌的情况,出牌情况分为:
    • zd 是否有炸弹,没有为 00,否则为炸弹的点数。
    • tb 是否有铁板,没有为 00,否则为铁板的点数。
    • n 是几牛,无牛为 00,牛牛为 1010,否则为牛数。
    • maxa 是最大卡牌,类型为 poker
    • id 即编号。
    _player 之间要先比较炸弹,再比较牛数,然后比较铁板,最后比较最大卡牌。
接下来我们可以按顺序来写。
我这里把每个回合的玩家用 _player 计为 p1p2p3

发牌

很明显,输入名字,二分找到 id,用字符串一个个输入卡牌,记录五张卡牌和最大卡牌。

出牌

我选择用五层循环枚举出牌方案,先尝试将前四张拼成炸弹,再尝试拼成牛,最后是无牛。用上文写的重载出来的运算符来比较不同牌组之间的大小这时就很方便了。

比较和计分

两两对比大小,再在底分 1010 上进行加倍,然后赢得加,输的减。
其实代码也不算很难,作者 60 分钟就打完了。由于我的写法时间复杂度为 3×T×55+3×T×log(n)3 \times T \times 5^5+3\times T\times \log(n),而且使用结构体的时间常数比较大,得用 C++98 才能过。
codeCPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+5;
int id,T,n;
struct p
{
	int id,ans;
	string name;
}player[maxn];
bool cmpname(p A,p B)
{
	return A.name<B.name;
}
bool cmpid(p A,p B)
{
	return A.id<B.id;
}
int findd(string x)
{
	int l=0,r=n+1;
	while(l+1<r)
	{
		int mid=l+r>>1;
	 	if(player[mid].name>=x)r=mid;
	 	else l=mid;
	}
	return r;
}
struct poker
{
	int hs,num;
};
bool operator < (poker A,poker B)
{
	if(A.num!=B.num)return A.num<B.num;
	else return A.hs>B.hs;
}
bool operator > (poker A,poker B)
{
	if(A.num!=B.num)return A.num>B.num;
	else return A.hs<B.hs;
}
struct _player
{
	int id;
	poker a[6];
	int zd;//是否是炸弹 
	int tb;//是否有铁板
	int n;//几牛,!无牛设为0 ,牛牛设为 10 
	poker maxa;
};
bool operator < (_player A,_player B)
{
	if(A.zd || B.zd)return A.zd<B.zd;//有炸弹,比较炸弹大小,没有炸弹为 0,不影响计算 
	if(A.n==B.n)//牛数一样 
	{
		if(A.tb || B.tb)return A.tb<B.tb;//比较铁板 
		return A.maxa<B.maxa;//比较最大牌 
	}
	return A.n<B.n;
}
bool operator > (_player A,_player B)
{
	return B<A;
}

_player sc(_player A)
{
	_player maxp=A;
	for(int i1=1;i1<=5;i1++)//五 
	{
		for(int i2=1;i2<=5;i2++)//层 
		{
			if(i1==i2)continue;
			for(int i3=1;i3<=5;i3++)//大 
			{
				if(i1==i3 || i2==i3)continue;
				for(int i4=1;i4<=5;i4++)//循 
				{
					if(i1==i4 || i2==i4 || i3==i4)continue;
					
					for(int i5=1;i5<=5;i5++)//环 
					{
						if(i1==i2 || i1==i3 || i1==i4 || i1==i5 || i2==i3 || i2==i4 || i2==i5 || i3==i4 || i3==i5 || i4==i5)
							continue;
						poker p1=A.a[i1],p2=A.a[i2],p3=A.a[i3],p4=A.a[i4],p5=A.a[i5];
						if(p1.num==p2.num && p2.num==p3.num && p3.num==p4.num)//炸弹 
						{
							A.zd=p1.num;
							A.tb=0;
							A.n=0;
							if(A>maxp)maxp=A;
							continue;
						}
						if(p1.num==p2.num && p2.num==p3.num)//铁板 
						{
							A.n=(p4.num+p5.num)%10;
							if(A.n==0)A.n=10;
							A.tb=p1.num;
							A.zd=0;
							if(A>maxp)maxp=A;
							continue;
						}
						if((p1.num+p2.num+p3.num)%10==0)//牛 
						{
							A.n=(p4.num+p5.num)%10;
							if(A.n==0)A.n=10;
							A.tb=0;
							A.zd=0;
							if(A>maxp)maxp=A;
							continue;
						}
						A.n=0,A.zd=0,A.tb=0;
						if(A>maxp)maxp=A;//无牛 
					}
				}
			}
		}
	}
	return maxp;
}
void ask(_player A,_player B)//比较并计分 
{
	if(A>B)
	{
		int s=10;
		if(A.zd)
		{
			s*=10;
		}
		else
		{
			if(A.n==10)s*=3;
			else if(A.n>=7)s*=2;
			if(A.tb)s*=2;
		}
		player[A.id].ans+=s;
		player[B.id].ans-=s;
		return;
	}
	int s=10;
	if(B.zd)
	{
		s*=10;
	}
	else
	{
		if(B.n==10)s*=3;
		else if(B.n>=7)s*=2;
		if(B.tb)s*=2;
	}
	player[B.id].ans+=s;
	player[A.id].ans-=s;
	return;
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
    cin>>id>>T>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>player[i].name;
    	player[i].id=i;
	}
	sort(player+1,player+1+n,cmpname);
	while(T--)
	{
		_player p1,p2,p3;
		string p;
		string name;
		cin>>name;
		p1.id=findd(name);
		p1.n=p1.tb=p1.zd=0;
		for(int i=1;i<=5;i++)
		{
			cin>>p;
			if(p[0]=='a')p1.a[i].hs=1;
			if(p[0]=='b')p1.a[i].hs=2;
			if(p[0]=='c')p1.a[i].hs=3;
			if(p[0]=='d')p1.a[i].hs=4;
			if(p[1]=='A')p1.a[i].num=1;
			else p1.a[i].num=p[1]-'0';
			if(p.size()==3)p1.a[i].num=10;
			if(i==1)p1.maxa=p1.a[i];
			else if(p1.a[i]>p1.maxa)p1.maxa=p1.a[i];
		}
		cin>>name;
		p2.id=findd(name);
		p2.n=p2.tb=p2.zd=0;
		for(int i=1;i<=5;i++)
		{
			cin>>p;
			if(p[0]=='a')p2.a[i].hs=1;
			if(p[0]=='b')p2.a[i].hs=2;
			if(p[0]=='c')p2.a[i].hs=3;
			if(p[0]=='d')p2.a[i].hs=4;
			if(p[1]=='A')p2.a[i].num=1;
			else p2.a[i].num=p[1]-'0';
			if(p.size()==3)p2.a[i].num=10;
			if(i==1)p2.maxa=p2.a[i];
			else if(p2.a[i]>p2.maxa)p2.maxa=p2.a[i];
		}
		cin>>name;
		p3.id=findd(name);
		p3.n=p3.tb=p3.zd=0;
		for(int i=1;i<=5;i++)
		{
			cin>>p;
			if(p[0]=='a')p3.a[i].hs=1;
			if(p[0]=='b')p3.a[i].hs=2;
			if(p[0]=='c')p3.a[i].hs=3;
			if(p[0]=='d')p3.a[i].hs=4;
			if(p[1]=='A')p3.a[i].num=1;
			else p3.a[i].num=p[1]-'0';
			if(p.size()==3)p3.a[i].num=10;
			if(i==1)p3.maxa=p3.a[i];
			else if(p3.a[i]>p3.maxa)p3.maxa=p3.a[i];
		}
		p1=sc(p1),p2=sc(p2),p3=sc(p3);
		ask(p1,p2);
		ask(p1,p3);
		ask(p2,p3);
	}
	sort(player+1,player+1+n,cmpid);
	for(int i=1;i<=n;i++)
	{
		cout<<player[i].name<<' '<<player[i].ans;
		cout<<'\n';
	}
    return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...