『模拟赛』暑假集训CSP提高模拟1

Rank

感冒了,同时心情极差,状态不好ww

image

A. Start

打磨你。

T1 放大模拟还是过于抽象了,开局劝退,遂倒序开题。

赛时想复杂了一点,开了两个二维数组存牌,同时存 double 状态时也出了问题,还没有考虑负数的向下取整。我太蒻了

改后虽然还是 300 多行,但是思路起码清晰了很多,改了几个小错就 A 了。

Code:
const int N=3e5+5;
const int mod=1e9+7;
int n,m,k,p,tot=1;
// tot 为牌堆摸取位置
string nam[6],have[6][4],paidui[N];
// 玩家名,玩家拥有手牌,牌堆
bool turnn,doubll,jp,endd;
// 分别表示出牌顺序,double 施加情况,解牌跳过 double,结束回合
// 由于 double 无论如何都是施加在下一个出牌的人身上的,所以一个变量就够
bool cmp(string a,string b)// 无 double 优先级排序
{
	int anum=-1,bnum=-1;
	if(a=="C2") anum=0;
	else if(a=="A99") anum=1;
	else if(a=="A49") anum=2;
	else if(a=="A19") anum=3;
	else if(a=="A9") anum=4;
	else if(a=="A5") anum=5;
	else if(a=="A2") anum=6;
	else if(a=="A1") anum=7;
	else if(a=="B1") anum=8;
	else if(a=="B9") anum=9;
	else if(a=="B19") anum=10;
	else if(a=="D2") anum=11;
	else if(a=="E99") anum=12;
	else if(a=="E49") anum=13;
	else if(a=="E0") anum=14;
	else if(a=="PASS") anum=15;
	else if(a=="TURN") anum=16;
	else if(a=="DOUBLE") anum=17;
	if(b=="C2") bnum=0;
	else if(b=="A99") bnum=1;
	else if(b=="A49") bnum=2;
	else if(b=="A19") bnum=3;
	else if(b=="A9") bnum=4;
	else if(b=="A5") bnum=5;
	else if(b=="A2") bnum=6;
	else if(b=="A1") bnum=7;
	else if(b=="B1") bnum=8;
	else if(b=="B9") bnum=9;
	else if(b=="B19") bnum=10;
	else if(b=="D2") bnum=11;
	else if(b=="E99") bnum=12;
	else if(b=="E49") bnum=13;
	else if(b=="E0") bnum=14;
	else if(b=="PASS") bnum=15;
	else if(b=="TURN") bnum=16;
	else if(b=="DOUBLE") bnum=17;
	return anum<bnum;
}
bool cmpd(string a,string b)// 有 double 优先级排序
{
	int anum=-1,bnum=-1;
	if(a=="PASS") anum=0;
	else if(a=="TURN") anum=1;
	else if(a=="DOUBLE") anum=2;
	else if(a=="D2") anum=3;
	else if(a=="B19") anum=4;
	else if(a=="B9") anum=5;
	else if(a=="B1") anum=6;
	else if(a=="A1") anum=7;
	else if(a=="A2") anum=8;
	else if(a=="A5") anum=9;
	else if(a=="A9") anum=10;
	else if(a=="A19") anum=11;
	else if(a=="A49") anum=12;
	else if(a=="A99") anum=13;
	else if(a=="C2") anum=14;
	else if(a=="E0") anum=15;
	else if(a=="E49") anum=16;
	else if(a=="E99") anum=17;
	if(b=="PASS") bnum=0;
	else if(b=="TURN") bnum=1;
	else if(b=="DOUBLE") bnum=2;
	else if(b=="D2") bnum=3;
	else if(b=="B19") bnum=4;
	else if(b=="B9") bnum=5;
	else if(b=="B1") bnum=6;
	else if(b=="A1") bnum=7;
	else if(b=="A2") bnum=8;
	else if(b=="A5") bnum=9;
	else if(b=="A9") bnum=10;
	else if(b=="A19") bnum=11;
	else if(b=="A49") bnum=12;
	else if(b=="A99") bnum=13;
	else if(b=="C2") bnum=14;
	else if(b=="E0") bnum=15;
	else if(b=="E49") bnum=16;
	else if(b=="E99") bnum=17;
	return anum<bnum;
}
// 排序保证选择普通牌顺序
namespace Wisadel
{
	int Wgetnext(int now)
	{// 找到下一个出牌的人
		if(turnn) now=(now==1?n:now-1);
		else now=(now==n?1:now+1);
		return now;
	}
	void Wworkjp(int now)
	{// 解牌优先
		bool can=0;
		sort(have[now]+1,have[now]+4,cmpd);
		// 按 double 优先级排序
		fo(i,1,3)
		{// 先考虑解牌
			string ss=have[now][i];
			if(ss=="PASS")
			{
				cout<<"used "<<ss<<",now p="<<p<<".\n";
				jp=1;can=1;// 直接跳过
				have[now][i]=paidui[tot++];// 取牌
				break;
			}
			else if(ss=="TURN")
			{
				cout<<"used "<<ss<<",now p="<<p<<".\n";
				jp=1;can=1;
				if(turnn) turnn=0;
				else turnn=1;// 反转出牌顺序
				have[now][i]=paidui[tot++];
				break;
			}
			else if(ss=="DOUBLE")
			{
				cout<<"used "<<ss<<",now p="<<p<<".\n";
				jp=1;can=1;
				doubll=1;// 记录 double 效果
				have[now][i]=paidui[tot++];
				break;
			}
		}
		if(can) return;
		// 若无解牌,则考虑基本牌
		int num=0,no,minn=1e9;
		fo(i,1,3)
		{// 考虑基本牌使用,按要求找最小值
			string ss=have[now][i];no=p;
			if(ss=="A1") no+=1;
			else if(ss=="A2") no+=2;
			else if(ss=="A5") no+=5;
			else if(ss=="A9") no+=9;
			else if(ss=="A19") no+=19;
			else if(ss=="A49") no+=49;
			else if(ss=="A99") no+=99;
			else if(ss=="B1") no-=1;
			else if(ss=="B9") no-=9;
			else if(ss=="B19") no-=19;
			else if(ss=="C2") no*=2;
			else if(ss=="D2") no=floor(1.0*no/2);
			else if(ss=="E0") no=0;
			else if(ss=="E49") no=49;
			else if(ss=="E99") no=99;
			else no=10000;
			if(no<=99&&no<minn) num=i,minn=no,can=1;
		}
		if(!can)
		{// 仍必败
			endd=1;
			cout<<"lost the game.\n";
		}
		else
		{// 可不败,打一摸一
			doubll=0;
			cout<<"used "<<have[now][num]<<",now p="<<minn<<".\n";
			have[now][num]=paidui[tot++];
			p=minn;
		}
	}
	void Wwork(int now)
	{// 普通牌优先
		sort(have[now]+1,have[now]+4,cmp);
		// 按无 double 优先级排序
		bool can=0;int num=0,no,maxx=-1e9;
		fo(i,1,3)
		{// 考虑基本牌使用,按要求找范围内最大值
			string ss=have[now][i];no=p;
			if(ss=="A1") no+=1;
			else if(ss=="A2") no+=2;
			else if(ss=="A5") no+=5;
			else if(ss=="A9") no+=9;
			else if(ss=="A19") no+=19;
			else if(ss=="A49") no+=49;
			else if(ss=="A99") no+=99;
			else if(ss=="B1") no-=1;
			else if(ss=="B9") no-=9;
			else if(ss=="B19") no-=19;
			else if(ss=="C2") no*=2;
			else if(ss=="D2") no=floor(1.0*no/2);
			else if(ss=="E0") no=0;
			else if(ss=="E49") no=49;
			else if(ss=="E99") no=99;
			else no=10000;
			if(no<=99&&no>maxx) num=i,maxx=no,can=1;
		}
		if(can)
		{// 能打则打一摸一
			cout<<"used "<<have[now][num]<<",now p="<<maxx<<".\n";
			p=maxx;
			have[now][num]=paidui[tot++];
			return;
		}
		fo(i,1,3)
		{// 否则考虑解牌
			string ss=have[now][i];
			if(ss=="PASS")
			{
				cout<<"used "<<ss<<",now p="<<p<<".\n";
				can=1;
				have[now][i]=paidui[tot++];
				break;
			}
			else if(ss=="TURN")
			{
				cout<<"used "<<ss<<",now p="<<p<<".\n";
				can=1;
				if(turnn) turnn=0;
				else turnn=1;
				have[now][i]=paidui[tot++];
				break;
			}
			else if(ss=="DOUBLE")
			{
				cout<<"used "<<ss<<",now p="<<p<<".\n";
				can=1;doubll=1;
				have[now][i]=paidui[tot++];
				break;
			}// 过程中直接打一摸一
		}
		if(!can)
		{// 必败
			endd=1;
			cout<<"lost the game.\n";
		}
	}
	short main()
	{
		// freopen("A.in","r",stdin),freopen("1.out","w",stdout);
		n=qr,m=qr,k=qr;
		fo(i,1,n) cin>>nam[i]>>have[i][1]>>have[i][2]>>have[i][3];
		fo(i,1,k) cin>>paidui[i];
		// 输入
		int laslos=1;
		// 从上回合熟的人开始,第一回合从 1 号开始
		fo(roundd,1,m)
		{
			printf("Round %d:\n",roundd);
			doubll=p=turnn=endd=0;int now=laslos;
			// 初始化标记变量
			while(1)
			{
				cout<<nam[now]<<' ';jp=0;
				if(doubll)
				{// 有 double 效果
					Wworkjp(now);
					// 先按 double 打一次
					if(jp)
					{// 使用了解牌,直接跳过
						now=Wgetnext(now);
						continue;
					}
					else if(endd)
					{// 败了
						laslos=now;
						if(roundd!=m)
						{// 重新摸牌
							have[now][1]=paidui[tot++];
							have[now][2]=paidui[tot++];
							have[now][3]=paidui[tot++];
						}
						break;
					}
					else 
					{// 否则按无 double 效果再进行一回合
						cout<<nam[now]<<' ';
						Wwork(now);
					}
				}
				else Wwork(now);
				// 无 double 效果
				if(endd)
				{// 败了
					laslos=now;
					if(roundd!=m)
					{
						have[now][1]=paidui[tot++];
						have[now][2]=paidui[tot++];
						have[now][3]=paidui[tot++];
					}
					break;
				}
				now=Wgetnext(now);
			}
		}
		return Ratio;
	}
}
int main(){return Wisadel::main();}

确实又臭又长了属于是。

咕一个长度在 150 行以内的,不无脑压行。


B. Mine

一个简单的 dp,但赛时倒数开的,时间不是很足,在暴搜上耽误很久。

所以以后看见题不能光想着搜了,脑子浑了就打醒之后考虑考虑 dp。

思路挺简单,讲的也很明白,不多写了。

C. 小凯的疑惑

数论题。同样最后开的这道题,压根没去想正解,要不是打 Subtask1 时候暴力摸出来了 Subtask2,这题就保龄了。

其实不互质无解挺显然的,但赛时没看出来,唐了。

然后远古的题考察化简式子化成 O(1) 的,但由于评测机的更新换代现在 108 的范围 O(n) 也能过,但还是没想出来。

image

粘一张推导,以后看。

D. 春节十二响

其实一眼泄题了不是吗

一道启发式合并。

题面挺简单的,起码看了 T1 之后这么想。

首先想的是树剖,每条链按类似田忌赛马的思想,最大值放在一起,次大值放在一起,以此类推,答案即为每一堆中最大值的和。

那么发现它是一种合并的思想,最后结果是得到了一条链,答案也就变成了这条链上的点权之和。

实现也不难,把每个父节点向子节点连一条单向边,dfs 到最深然后逐层合并,每条链的头没有对应的点,合并后再加入,链用优先队列维护很方便。

Code:
const int N=4e6+5;
int n;
ll ans;
int a[N],zc[N],id[N],tot;
int hh[N],to[N],ne[N],cnt;
priority_queue<int>q[N];
namespace Wisadel
{
	void Wadd(int u,int v)
	{
		to[++cnt]=v;
		ne[cnt]=hh[u];
		hh[u]=cnt;
	}
	void Wmerge(int x,int y)
	{
		if(q[id[x]].size()<q[id[y]].size()) swap(id[x],id[y]);
		int len=q[id[y]].size();
		fo(i,1,len)
			zc[i]=max(q[id[x]].top(),q[id[y]].top()),
			q[id[x]].pop(),q[id[y]].pop();
		fo(i,1,len) q[id[x]].push(zc[i]);
	}
	void Wdfs(int u)
	{
		id[u]=++tot;
		for(int i=hh[u];i!=-1;i=ne[i])
		{
			int v=to[i];
			Wdfs(v);
			Wmerge(u,v);
		}
		q[id[u]].push(a[u]);
	}
	short main()
	{
		memset(hh,-1,sizeof hh);
		n=qr;int f;
		fo(i,1,n) a[i]=qr;
		fo(i,2,n) f=qr,Wadd(f,i);
		Wdfs(1);
		while(q[id[1]].size()) ans+=q[id[1]].top(),q[id[1]].pop();
		printf("%lld\n",ans);
		return Ratio;
	}
}
int main(){return Wisadel::main();}

完结撒花~

久违了

posted @   Ratio_Y  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示