2021牛客暑期多校夏令营第二场

前言

实训中, 中午11点半放学, 下午2点上课, 12点的比赛…
11点提前溜了, 随便吃了点就赶回来了, 据说实验室停空调了, 正好在教室打比赛.
比赛开始我和yl一人A了一道签到, 然后我去看K, yl和jwr去看F, 我推了一个小时发现思路错了, 紧急呼叫yl回来看K. 然后他半个小时A了… 我去找其他题, 发现I是个搜索题, 心想上场比赛的搜索我wa了, 这场一定要一雪前耻! 然后又wa了… F题也是, 公式推出来了, 但最后相交的体积感觉求得有一些问题, 样例能过, 数据过不去. yl来改我的I题, 觉得是字典序的问题, 但应该不是. 最后3题罚坐.
赛后通过yym的指点, 发现自己I题犯了一个很蠢的问题, 具体题干里说


C. Draw Grids

题意

两人对n * m的区域分别进行连线, 不能有环, 走不了的人输

分析

求一个图的最小生成树边数, 对点的数量求奇偶即可

代码(队友的)

#include<bits/stdc++.h>
using namespace std;
int n,m;

int main()
{
	cin>>n>>m;
	if((n*m)&1) cout<<"NO";
	else cout<<"YES";
	return 0;
}

D. Er Ba Game

题意

两个人每人俩数字, 比大小

分析

模拟就完事了, 我写了一堆if else, 非常丑陋

代码

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

int t;
int a1, b1, a2, b2;

int main(void)
{
	cin >> t;
	while (t --)
	{
		cin >> a1 >> b1 >> a2 >> b2;
		if (a1 > b1)	swap(a1, b1);
		if (a2 > b2)	swap(a2, b2);
		
		if (a1 == 2 && b1 == 8)
		{
			if (a2 == 2 && b2 == 8)	puts("tie");
			else	puts("first");
		}
		else
		{
			if (a2 == 2 && b2 == 8)	puts("second");
			else
			{
				if (a1 == b1)
				{
					if (a2 == b2)
					{
						if (a1 > a2)	puts("first");
						else if (a2 > a1)	puts("second");
						else	puts("tie");
					}
					else	puts("first");
				}
				else
				{
					if (a2 == b2)	puts("second");
					else
					{
						if ((a1 + b1) % 10 > (a2 + b2) % 10)	puts("first");
						else if ((a1 + b1) % 10 < (a2 + b2) % 10)	puts("second");
						else
						{
							if (b1 > b2)	puts("first");
							else if (b2 > b1)	puts("second");
							else	puts("tie");
						}
					}
				}
			}
		}
	}
	return 0;
}

F. Girlfriend

题意

根据两点之间的距离不小于k倍, 得到两个球, 求这两个球的公共体积

分析

比赛的时候才知道这东西叫阿尼波斯圆, 有一个公式专门求公共部分体积, 比赛的时候硬推的, 只推出了平面内成立的情况, 空间中还有很多情况没考虑到

代码

//后续补充

I. Penguins

题意

俩企鹅, 分别在两幅图里走, 走的上下方向相同, 左右方向相反, 撞墙了就不会往前走, 输出最后的路径

分析

很明显一道搜索题, 只是要同时对两幅图进行搜索, 一开始思路是开两个队列分别进行广搜, 但发现二者是同时进行的, 因此把思路转变为开一个四维的数组, 对每一个同时到达位置进行标记, 按照字典序进行输出即可
但是比赛的时候犯了一个很严重的失误, 最后在输出的时候, 我选择记录每个点是从哪个点走过来的. 这种方法在只有一幅图的时候显然是可行而且比较好的, 但是有两幅图, 左边的企鹅可能在某一步不动才是结果最优, 这样就不知道"不动"的这次方向是哪里了, 因此导致最终结果完全错误了
经过yym的指点, 代码简单加上一个方向的判断就过了

代码

#include<cstdio>
#include<queue>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;

const int N = 22;

typedef struct node{
	int x1, y1, x2, y2;
}Node;

char g1[N][N], g2[N][N];
int n = 20;
int dx1[4] = {1, 0, 0, -1}, dy1[4] = {0, -1, 1, 0};
int dx2[4] = {1, 0, 0, -1}, dy2[4] = {0, 1, -1, 0};
bool st[N][N][N][N];

string s;

int ope[N][N][N][N]; 
Node pre[N][N][N][N];

Node bfs()
{
	queue<node> q;
	q.push({19, 19, 19, 0});
	st[19][19][19][0] = true;
	pre[19][19][19][0] = {-1, -1, -1, -1};
	
	while (q.size())
	{
		Node temp = q.front();
		q.pop();
		
		int tx1 = temp.x1, tx2 = temp.x2, ty1 = temp.y1, ty2 = temp.y2;
		
		if (tx1 == 0 && ty1 == 19 && tx2 == 0 && ty2 == 0)	return {tx1, ty1, tx2, ty2};
		
		for (int i = 0; i < 4; i ++)
		{
			bool flag1 = true, flag2 = true;
			int nx1 = tx1 + dx1[i], ny1 = ty1 + dy1[i], nx2 = tx2 + dx2[i], ny2 = ty2 + dy2[i];
			if (nx1 < 0 || ny1 >= n || ny1 < 0 || nx1 >= n || g1[nx1][ny1] == '#')
			{
				flag1 = false;
				nx1 = tx1, ny1 = ty1;
			}
			if (nx2 < 0 || nx2 >= n || ny2 < 0 || ny2 >= n || g2[nx2][ny2] == '#')
			{
				flag2 = false;
				nx2 = tx2, ny2 = ty2;
			}
			
			
			if (!flag1 && !flag2)	continue;
			if (st[nx1][ny1][nx2][ny2])	continue;
			
			st[nx1][ny1][nx2][ny2] = true;
			pre[nx1][ny1][nx2][ny2] = {tx1, ty1, tx2, ty2};
			ope[nx1][ny1][nx2][ny2] = i;
			q.push({nx1, ny1, nx2, ny2});
		}
	}
}

char dir(int x1, int y1, int x2, int y2)
{
	if (x2 - x1 == 1)	return 'D';
	if (x2 - x1 == -1)	return 'U';
	if (y2 - y1 == 1)	return 'R';
	if (y2 - y1 == -1)	return 'L';
}

int main(void)
{
	for (int i = 0; i < n; i ++)
	{
		scanf("%s", g1[i]);
		scanf("%s", g2[i]);
	}
	
	int cnt = 0;
	Node t = bfs();
	Node l = pre[t.x1][t.y1][t.x2][t.y2];
	char op[]={'D','L','R','U'};
	while (l.x1 != -1)
	{
		g1[t.x1][t.y1] = 'A';
		g2[t.x2][t.y2] = 'A';
		s += op[ope[t.x1][t.y1][t.x2][t.y2]];
		t = l;
		l = pre[t.x1][t.y1][t.x2][t.y2];
		cnt ++;
	}
	g1[t.x1][t.y1] = 'A';
	g2[t.x2][t.y2] = 'A';
	
	printf("%d\n", cnt);
	reverse(s.begin(), s.end());
	cout << s << endl;
	for (int i = 0; i < n; i ++)
	{
		printf("%s %s\n", g1[i], g2[i]);
	}
	
	return 0;
}

总结

比赛时候还是应该多想一些可能情况的样例, 来方便进行调试, 本来以为是字典序的问题, 也构造了一组卡掉字典序的样例, 后来发现没问题, 还是想的少了一些


K. Stack

题意

给出一个单调栈计算到每个位置的时候栈内有多少元素, 求出原序列

分析

题解是使用拓扑排序, 或链表模拟的方式, 和湘潭邀请赛中的那个stack问题有点类似, 比赛的时候我想的方法比较复杂, 最终没有推导出来

代码(队友的)

//后续补充
#include<bits/stdc++.h>
#define PB(x) push_back(x)
#define pop() pop_back()
using namespace std;
const int N=1e6+9;
int n,k;
int a[N],vis[N],c[N];
vector<int>mi,ma;
struct node
{
	int p,x;
	bool operator < (const node &y) const
	{
		return p<y.p;
	}
}b[N];

int main()
{
	cin>>n>>k;
	for(int i=1;i<=k;i++)
		cin>>b[i].p>>b[i].x;
	sort(b+1,b+1+k);
	memset(c,-1,sizeof(c));
	for(int i=1;i<=k;i++)
	{
		c[b[i].p]=b[i].p-b[i].x;
		if(c[b[i].p]<0)
		{
			cout<<-1;
			return 0;
		}
	}
	c[0]=0;
	for(int i=1;i<=n;i++)
	{
		if(c[i]==-1) c[i]=c[i-1];
		if(c[i]<c[i-1])
		{
			cout<<-1;
			return 0;
		}
	}
	a[n]=n-c[n];
	mi.PB(a[n]-1);
	ma.PB(a[n]+1);
	vis[a[n]]=1;
	for(int i=n-1;i>=1;i--)
	{
		while(mi.size()&&(vis[mi.back()]||mi.back()<1||mi.back()>n)) mi.pop();
		while(ma.size()&&(vis[ma.back()]||ma.back()<1||ma.back()>n)) ma.pop();
		if(c[i]==c[i+1])
		{
			if(mi.empty())
			{
				cout<<-1;
				return 0;
			}
			a[i]=mi.back();
			mi.pop();
			mi.PB(a[i]-1);
		}
		else
		{
			if(ma.empty())
			{
				cout<<-1;
				return 0;
			}
			a[i]=ma.back()+c[i+1]-c[i]-1;
			ma.pop();
			ma.PB(a[i]+1);
			mi.PB(a[i]-1);
		}
		vis[a[i]]=1;
	}
	for(int i=1;i<=n;i++)
		cout<<a[i]<<" ";
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值