USACO 2021 US Open, Bronze(铜组测试四)解题报告

USACO 2021 US Open, Bronze(铜组测试四)解题报告

---------------cadifobp0802

T1 奶牛的学术圈 I

问题描述

由于对计算机科学的热爱,以及有朝一日成为 「Bessie 博士」的诱惑,奶牛 Bessie 开始攻读计算机科学博士学位。经过一段时间的学术研究,她已经发表了 N 篇论文(),并且她的第 i 篇论文得到了来自其他研究文献的 ci 次引用()。

Bessie 听说学术成就可以用 h 指数来衡量。h 指数等于使得研究员有至少 h 篇引用次数不少于 h 的论文的最大整数 h。例如,如果一名研究员有 4 篇论文,引用次数分别为 (1,100,2,3),则 h 指数为 2,然而若引用次数为 (1,100,3,3) 则 h 指数将会是 3。

为了提升她的 h 指数,Bessie 计划写一篇综述,并引用一些她曾经写过的论文。由于页数限制,她至多可以在这篇综述中引用 L 篇论文(),并且她只能引用每篇她的论文至多一次。

请帮助 Bessie 求出在写完这篇综述后她可以达到的最大 h 指数。

注意 Bessie 的导师可能会告知她纯粹为了提升 h 指数而写综述存在违反学术道德的嫌疑;我们不建议其他学者模仿 Bessie 的行为。

输入格式

输入的第一行包含 N 和 L。

第二行包含 N 个空格分隔的整数 c1,…,cN。

输出格式

输出写完综述后 Bessie 可以达到的最大 h 指数。

输入样例

4 0
1 100 2 3

输出样例

2

样例说明

Bessie 不能引用任何她曾经写过的论文。上文中提到,(1,100,2,3) 的 h 指数为 2。

输入样例

4 1
1 100 2 3

输出样例:

3

样例说明

如果 Bessie 引用她的第三篇论文,引用数会变为 (1,100,3,3)。上文中提到,这一引用数的 h 指数为 3。

我的想法

由于每篇文章的引用数最多才会增加1,所以h实际上最多也会增加1。那就只需要先排序,然后找到原来的h指数,然后看第h+1篇文章是否等于h,且需要被引用的文章数小于L。
代码如下:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 100010

int n, at[MAXN], l, h = n;

bool cmp (int p, int q){
	return p > q;
}

int main(){
    //freopen("prob1.in","r",stdin);
    //freopen("prob1.out","w",stdout);
    cin >> n >> l;
    for (int i = 1; i <= n; ++i)
		cin >> at[i];
	sort(at + 1, at + n + 1, cmp);
	for (int i = 1; i <= n; ++i) {
		if (at[i] < i) {
			h = i;
			break;
		}
	}//找h指数
	if (at[h] + 1 < h)
		h -= 1;
	else {
		int t = 0;
		for (int i = 1; i <= h; ++i)
			if (at[i] + 1 == h)
				t++;
		if (t > l)
			h -= 1;//判断引用次数是否高于l
	}
	cout << h << endl;
    //fclose(stdin);
    //fclose(stdout);
	return 0;
}

T2 奶牛的学术圈 II

问题描述

Bessie 正在申请计算机科学的研究生,并取得了一所久负盛名的计算机科学实验室的面试通知。然而,为了避免冒犯任何人,Bessie 有意先确定实验室的 N 名现有成员的相对资历(1≤N≤100)。没有两名实验室成员的资历相同,但确定他们的资历深浅可能并不好办。为此,Bessie 将会对实验室的出版物进行调查。

每份出版物均包含一个作者列表,为所有 N 名实验室成员的一个排列。列表按每名实验室成员对这篇文章的贡献降序排列。如果多名研究员的贡献相等,则按字典序排列。由于更有资历的实验室成员负有更多的管理责任,更有资历的研究员从不会比资历较浅的研究员做出更多的贡献。

例如,在一个由资历较浅的学生 Elsie、资历较深的教授 Mildred、以及十分资深的教授 Dean 组成的实验室中,可能存在一篇论文 Elsie-Mildred-Dean,如果他们做出了不等的贡献(也就是说,Elsie 做出的贡献比 Mildred 更多,Mildred 比 Dean 更多)。然而,也有可能存在一篇论文 Elsie-Dean-Mildred,如果 Mildred 和 Dean 做出了相等的贡献,而 Elsie 做出了更多的贡献。

给定实验室的 K 份出版物(1≤K≤100),对于实验室中每对研究员,如果可能的话帮助 Bessie 判断其中谁的资历更深。

输入格式

输入的第一行包含两个整数 K 和 N。

第二行包含 N 个空格分隔的字符串,为实验室的成员的名字。每个字符串均由小写字母组成,且至多包含 10 个字符。

以下 K 行,每行包含 N 个空格分隔的字符串,表示一份出版物的作者列表。

输出格式

输出 N 行,每行 N 个字符。在第 i 行内,对于所有 j≠i,当可以确定第 i 名成员比第 j 名成员资历更深时字符 j 为 1,当可以确定第 i 名成员比第 j 名成员资历更浅时字符 j 为 0,当不能由给定的出版物确定时为 ?。

第 i 行的字符 i 应为 B,因为这是 Bessie 最喜欢的字母。

输入样例

1 3
dean elsie mildred
elsie mildred dean

输出样例

B11
0B?
0?B

样例说明

在这个样例中,单独一份论文 elsie-mildred-dean 并不能提供足够的信息判断 Elsie 比 Mildred 资历更深或更浅。然而,我们可以推断出 Dean 一定比这两名研究员资历更深,从而资历排序为 Elsie<Mildred<Dean 和 Mildred<Elsie<Dean 均是可能的。

输入样例

2 3
elsie mildred dean
elsie mildred dean
elsie dean mildred

输出样例

B00
1B0
11B

样例说明

在这个样例中,唯一能与两篇论文相一致的资历排序为Elsie<Mildred<Dean,这是因为基于第一个样例所提供的信息,第二篇论文可以帮助我们推断出 Mildred 比 Elsie 的资历更深。

我的想法

可以把每一次的成员名称序列按字典序分割,如果后一个名字比前一个名字字典序要小,那么相当于升了一级,后面的成员都比前面的成员资历要深。用map映射每个成员的序号存到数组中。
代码如下:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 110

int k, n, a[MAXN][MAXN];
string s[MAXN];
map<string, int> m;

bool cp(string p, string q) {
	int l = p.size(), l2 = q.size();
	int len = min(l, l2);
	for (int i = 0; i < len; ++i) {
		if (p[i] < q[i])
			return true;
		else if (p[i] > q[i])
			return false;
	}
	if (l > len)
		return false;
	return true;
}
//字典序比较,如果p在q前面返回true
int main(){
	//freopen("prob2.in","r",stdin);
	//freopen("prob2.out","w",stdout);
	memset(a, -1, sizeof(a));
	cin >> k >> n;
	for (int i = 1; i <= n; ++i) {
		string str;
		cin >> str;
		m[str] = i;
	}
	while (k--){
		int t = 1;
		for (int i = 1; i <= n; ++i) {
			cin >> s[i];
			if (cp(s[i], s[i - 1]))
				t = i;
			for (int j = 1; j < t; ++j) {
				a[m[s[j]]][m[s[i]]] = 0;
				a[m[s[i]]][m[s[j]]] = 1;
			}//把能确定的计入答案数组中
		}
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
			if (i == j)
				printf("B");
			else if (a[i][j] == -1)
				printf("?");
			else {
				printf("%d", a[i][j]);
			}
		}
		printf("\n");
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}

T3 奶牛的学术圈 III

问题描述

Bessie 是一位忙碌的计算机科学研究生。然而,即使是研究生也需要交友。因此,Farmer John 开设了一片草地,目的是为了帮助 Bessie 与其他奶牛建立持久的友谊。

Farmer John 的草地可以被看做是由正方形方格组成的巨大二维方阵(想象一个巨大的棋盘)。每个方格用如下字符标记:

C,如果这个方格中有一头奶牛。
G,如果这个方格中有草。
.,如果这个方格既没有奶牛也没有草。
对于两头想要成为朋友的奶牛,她们必须选择在一个与她们均水平或竖直方向上相邻的有草方格见面。在这个过程中,她们会在这个有草方格中吃草,所以之后的奶牛不能再使用这个方格作为见面地点。一头奶牛可以与多头其他奶牛成为朋友,但是同一对奶牛不能见面并成为朋友多于一次。

Farmer John 希望有许多奶牛可以见面并成为朋友。请求出当这一活动结束时在奶牛之间可以建立的朋友关系的最大数量。

输入格式

输入的第一行包含 N 和 M(1≤N,M≤1000)。

以下 N 行每行包含一个由 M 个字符组成的字符串,表示这个草地。

输出格式

输出在这一活动结束时在奶牛之间可以建立的朋友关系的最大数量。

输入样例

4 5
.CGGC
.CGCG
CGCG.
.CC.C

输出样例

4

样例说明

如果我们用坐标 (i,j) 标记第 i 行第 j 列的奶牛,则在这个样例中于 (1,2)、(1,5)、(2,2)、(2,4)、(3,1)、(3,3)、(4,2)、(4,3) 以及 (4,5) 存在奶牛。一种使四对奶牛成为朋友的方式如下:

位于 (2,2) 和 (3,3) 的奶牛于 (3,2) 一起吃草。
位于 (2,2) 和 (2,4) 的奶牛于 (2,3) 一起吃草。
位于 (2,4) 和 (3,3) 的奶牛于 (3,4) 一起吃草。
位于 (2,4) 和 (1,5) 的奶牛于 (2,5) 一起吃草。

测试点性质

测试点 2-4 满足 N=2。
测试点 5-12 没有额外限制。

我的想法

可以去查找草的位置。如果一棵草周围只有不到两头牛,那么不会有牛来;如果有大于两头牛,可以使相对的两头牛来交友(这两头牛只有这一种可能的交友方式,不会重复);如果正好等于两头,那么如果这两头牛没有事先交过友的话,成功交友。
代码如下:

#include <bits/stdc++.h>
using namespace std;
#define MAXN 1010

const int dx[] = {-1, 0, 0, 1};
const int dy[] = {0, -1, 1, 0};
const int dxx[] = {-2, -1, 0, 1, 2, 1, 0, -1};
const int dyy[] = {0, -1, -2, 1, 0, -1, 2, 1};

int n, m, ans = 0, t = 0;
char a[MAXN][MAXN];
short vh[MAXN][MAXN][10];

int main(){
	//freopen("prob3.in","r",stdin);
    //freopen("prob3.out","w",stdout);
    memset(vh, -1, sizeof(vh));
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
    	for (int j = 1; j <= m; ++j) {
    		cin >> a[i][j];
		}
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j) {
			if (a[i][j] == 'G') {
				int cnt = 0;
				for (int k = 0; k <= 3; ++k) {
					int h = i + dx[k], l = j + dy[k];
					if (a[h][l] == 'C')
						cnt++;
				}
				//cout << cnt << endl;
				if (cnt > 2)
					ans++;//大于2相对相见
				else if (cnt == 2) {
					int x1 = -1, x2 = -1, y1 = -1, y2 = -1;
					for (int k = 0; k <= 3; ++k) {
						int h = i + dx[k], l = j + dy[k];
						if (a[h][l] == 'C') {
							if (x1 == -1) {
								x1 = h;
								y1 = l;
							}
							else {
								x2 = h;
								y2 = l;
							}
						}
					}
					//cout << x1 << " " << y1 << " " << x2 << " " << y2 << endl;
					int xx = x2 - x1, yy = y2 - y1, ii, iii;
					for (int k = 0; k <= 7; ++k) {
						if (dxx[k] == xx && dyy[k] == yy)
							ii = k;
						else if (dxx[k] == -xx && dyy[k] == -yy)
							iii = k;
					}
					if (vh[x1][y1][ii] == -1 && vh[x2][y2][iii] == -1) {
						ans++;
						vh[x1][y1][ii] = vh[x2][y2][iii] = ++t;
					}
				}//只有两头牛相邻的话判断有没有出现过,这里是用的vh标记两头牛相对位置(每头牛最多可能和8头牛交友),也可以用别的方法
			}
		}
	cout << ans << endl;
    //fclose(stdin);
	//fclose(stdout);
	return 0;
}
### 回答1: USACO 2021年12月是美国计算机奥林匹克竞赛的一次比赛,是为了选拔美国高中生中最优秀的计算机科学家而举办的。比赛包括个不同难度级别的编程题目,参赛者需要在规定时间内完成这些题目。这次比赛的题目难度较高,需要参赛者具备较强的编程能力和算法思维能力。 ### 回答2: usaco是一个很受欢迎的美国高中生和大学生参加的计算机竞赛,每年会有场不同的赛事,分为铜组、银组、金组和白银组等4个不同级别。2021年12月的usaco比赛题目难度中等,共4道算法题,主要涉及搜索算法、贪心算法、动态规划和图论算法等方面内容。 题目一是“Convenience Store”,给定一个城市地图,其中包含n个建筑,每个建筑位置有xy坐标,建筑之间可能有道路连通,每个建筑中包含一个便利店和售货员,售货员需要把货物直接送到顾客的门口并统计物资,问售货员需要访问哪些建筑才能完成任务。 题目二是“Longest Path Game”,给定一个有向无环图和起点和终点,每次可以走向图中指向该点的其他点,每走一步需要支付一定的代价,问从起点到终点最少需要支付多少代价并给出最少花费路径。 题目三是“Escape”,给定一个大小为n*m的迷宫,其中包含空地和只能通过特殊方式通过的障碍物,新增一个道具可以消除障碍物,在指定时间内到达终点即可获胜,问是否存在可行解。 题目是“New Year Travel”,给定一个n个城市构成的圆环和m条单向道路,初次n个城市顺时针排列,经过m次之后重排该圆环,问是否存在一条路径可以在经过圆环的最小路程的前提下遍历所有的城市。 ### 回答3: USACO 2021 12月是一次由美国计算机科学奥林匹克联赛(USACO)组织的编程竞赛。USACO是美国高中生最具影响力的计算机竞赛之一,每年分为个季度,包含铜组、银组、金组和白金组,涵盖了算法设计、数据结构、图论、搜索、动态规划、计算几何、图像处理等多个领域和真实场景。 本场比赛共有铜组、银组和金组三个组别,其中铜组和银组为在线比赛,金组为24小时比赛。比赛难度较高且时间较紧,需要选手在有限时间内完成一系列复杂的程序设计题目。在比赛期间,选手需要具备良好的分析问题、设计算法和编写程序的能力,同时还需要有过硬的数学基础、英语阅读理解能力和编程实践经验。 对于铜组选手来说,需要能够熟练使用基本算法和数据结构来解决题目,如模拟、暴力搜索、递推等;对于银组选手,则需要有更深入的算法思考和程序实现能力,如分治、贪心、二分、动态规划等;而针对金组选手,需要更高的算法挑战和程序优化能力,如图论、网络流、计算几何等。 此次USACO 2021 12月比赛题目难度较大,需要选手们具备扎实的算法基础和良好的程序设计习惯。要想在比赛中取得好成绩,需要选手们克服紧张心理,在比赛前加强对算法知识和代码实践的学习,时刻保持冷静,清晰思路,在有限时间内充分展现自己的编程才能和思维能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值