ACM训练【2021/9/16】

题目描述:

在 Berland 流行着纸牌游戏 “Berlogging” ,这个游戏的赢家是根据以下规则确定的:在每一轮中,玩家获得或失去一定数量的分数,在游戏过程中,分数被记录在“名称和得分”行中,其中名字是玩家的名字,得分是在这一轮中获得的分数。得分是负值意味着玩家失去了相应的分数。如果在比赛结束时只有一名玩家分数最多,他就是获胜者。如果两名或两名以上的玩家在比赛结束时都有最大的分数 m,那么其中首先获得至少 m 分的玩家胜利。开始时,每个玩家都是0分。保证在比赛结束时至少有一个玩家的分数为正。

输入格式:

第一行包含整数n(1 <= n <= 1000),n 是游戏进行的的回合数。

第 2 ~ n+1 行,按照时间顺序输入“名称和得分”行的信息,其中名称是长度不大于 32 的小写字母组成的字符串,分数的绝对值不大于 1000。

输出格式:

输出获胜者的名称。

输入输出样例

输入 #1

3
mike 3
andrew 5
mike 2

输出 #1

andrew

题解:我们先定义string对应int的map映射。对每次输入进来的人名进行对应的分数操作。
但是,有可能会出现比赛结束后最大分相等的情况。所以我们就要结束之后再访问一遍,查找第一次大于等于最大分的情况。其他需要注意的地方这道题似乎就没有了。剩下的就是最基础的调用map。但是在最后最高分数不止一人的时候,找的获胜者是首先获得至少 m 分的玩家胜利,还要保证自己到最后的分数为最大者之一(自己第一次漏了这一点)!!!

AC代码:

#include<iostream>
#include<queue>
#include<map>
#include<cstdio>
#include<algorithm>
#define INF 0x3f3f3f3f
using namespace std;
map<string,int>mp;
map<string,int>Q;
map<string,int>dp;
struct node{
	string s;
	int num;
}room[1005];	
int main(){
	int t;
	string ss[1005];
	scanf("%d",&t);
	for(int i=1;i<=t;i++){
		string str;
		int k;
		cin>>str>>k;
		room[i].s=str;room[i].num=k;
		mp[str]+=k;
		Q[str]=i;
		ss[i]=str;
	}
	int sum=0;
	for(map<string,int>::iterator it=mp.begin();it!=mp.end();it++){
		if(it->second>=sum){
			sum=it->second;
		}
	}
	int flat=INF;
	for(int i=1;i<=t;i++){
		dp[room[i].s]+=room[i].num;
		if(dp[room[i].s]>=sum&&mp[room[i].s]==sum){
			flat=i;break;
		}
	}
	cout<<ss[flat]<<endl;
}

题意描述:

当然,大家都熟悉井字棋游戏。 这些规则确实很简单。 两个玩家A、B轮流在3x3的方格的单元格中画符号(玩家A总是画“X”,玩家B总是画“0”)。 首先在水平、垂直或对角线上出现3个相同的符号的玩家获胜,比赛结束。 玩家A总是为先手。 如果3x3的方格被填满,但是在所有水平、垂直或对角线上均未出现3个相同的符号,宣布平局。

给你一个3*3的方格,每个单元格是“.”(空白),“X”或“0”。 你必须输出以下内容之一:

玩家A走棋(输出“first”)——如果出现给定的状态后,下一步为玩家A走棋。

玩家B走棋(输出“second”)——如果出现给定的状态后,下一步为玩家B走棋。

非法(输出“illegal”)——如果给定的状态无法在正常游戏过程中出现。

玩家A胜利(输出“the first player won”)——如果给定的状态中玩家A胜利。

玩家B胜利(输出“the second player won”)——如果给定的状态中玩家B胜利。

平局(输出“draw”)——如果给定的状态是平局。

输入输出样例

输入 #1

X0X
.0.
.X.

输出#1

second

输入 #2

XXX
0X0
X00

输出#2

the first player won

题解:

采用暴力枚举的方法,把每一种可能的情况都枚举一遍,时间复杂度O(1)。
注意illegalillegal的情况比较多,有以下几种:
(1)"0"的个数比"X"多。
(2)"X"的个数比"0"多两个及以上。
(3)先手获胜,但"0"的个数和"X"的个数一样。
(4)后手获胜,但"X"的个数比"0"的个数多1。
(5)先手和后手同时获胜。

如果棋盘是合法的,再判断谁输谁赢,或者是否是和棋。如果棋还没有下完,就判断该谁下了,如果"X"的个数和"0"的个数一样,就该先手走棋;如果"X"的个数比"0"多1,则该后手走棋。

AC代码:

#include<map>
#include<iostream>
#include<cmath>
#include<vector>
#include<string>
#include<cmath>
#include<iomanip>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int main(){
	string  s[10];
	for(int i=0;i<3;i++){
		cin>>s[i];
	}
	int word=0;
	int x=0,o=0;
	for(int i=0;i<3;i++){
		if(s[i].size()!=3){
			word=1;break;
		}
		for(int j=0;j<3;j++){
			if(s[i][j]!='.'&&s[i][j]!='X'&&s[i][j]!='0'){
				word=1;break;
			}
			if(s[i][j]=='X') x++;
			else if(s[i][j]=='0') o++;
		}
	}
	//cout<<word<<endl;
	if(word){cout<<"illegal"<<endl;return 0;}
	int flat=0;
	for(int i=0;i<3;i++){
		if(s[i][0]=='X'&&s[i][1]=='X'&&s[i][2]=='X'){
			flat++;
		}
	}
	for(int i=0;i<3;i++){
		if(s[0][i]=='X'&&s[1][i]=='X'&&s[2][i]=='X'){
			flat++;
		}
	}
	if(s[0][0]=='X'&&s[1][1]=='X'&&s[2][2]=='X') flat++;
	if(s[0][2]=='X'&&s[1][1]=='X'&&s[2][0]=='X') flat++;
	int ans=0;
	for(int i=0;i<3;i++){
		if(s[i][0]=='0'&&s[i][1]=='0'&&s[i][2]=='0'){
			ans++;
		}
	}
	for(int i=0;i<3;i++){
		if(s[0][i]=='0'&&s[1][i]=='0'&&s[2][i]=='0'){
			ans++;
		}
	}
	if(s[0][0]=='0'&&s[1][1]=='0'&&s[2][2]=='0') ans++;
	if(s[0][2]=='0'&&s[1][1]=='0'&&s[2][0]=='0') ans++;
	//cout<<ans<<' '<<flat<<endl;
	//if(ans>1||flat>1){cout<<"illegal"<<endl;return 0;}
	if(ans!=0&&flat!=0) {cout<<"illegal"<<endl;return 0;}
	int sum=x-o;
	if(fabs(sum)==1||fabs(sum)==0){
		if(x<o) {cout<<"illegal"<<endl;return 0;}
		if(x>o){
			if(x+o==9){
				if(flat==0&&ans==0){cout<<"draw"<<endl;return 0;}
				if(flat!=0&&ans==0){cout<<"the first player won"<<endl;return 0;}
				if(flat==0&&ans!=0){cout<<"the second player won"<<endl;return 0;}
			}
			else{
				if(flat!=0&&ans==0){cout<<"the first player won"<<endl;return 0;}
				if(ans!=0) {cout<<"illegal"<<endl;return 0;}
				cout<<"second"<<endl;return 0;
			}
		}
		else if(x==o) {
			if(flat!=0) {cout<<"illegal"<<endl;return 0;}
			if(ans!=0) {cout<<"the second player won"<<endl;return 0;}
			cout<<"first"<<endl;return 0;
		}
	}
	else {cout<<"illegal"<<endl;return 0;}
}

题意翻译

题目描述

第一个国家级操作系统——BerlOS就要发布了。但是,它的一些功能还没有完善,比如内存管理系统。在开发者的计划里,第一版里的内存管理系统是简单并且是线性的。它将会支持以下操作:

alloc n —— 在内存中分配n字节的空间。此命令将返回已分配的内存块的编号x。

erase x —— 释放编号为x的内存块。
defragment —— 碎片整理,将所有内存块全部向内存的起点靠拢并且不改变它们的顺序。

整条内存一共有m个字节,每个字节依次编号为1,2,...,m。

操作 alloc 有一个参数n,表示需要分配n字节大小的内存块。在执行这个操作时,系统将把一块最靠近内存起点的,长度为n的连续空闲字节分配到一个内存块(这块内存块内的所有字节将被标记为“已使用”)。这个操作的返回值为这块内存块的编号。如果没有符合条件的内存块,返回 NULL 。

操作 erase 有一个参数x,表示需要释放的内存块的编号。它将释放这个内存块(这块内存块内的所有字节将被标记为“空闲”)。如果成功释放,不返回值;如果编号为x的内存块不存在,返回 ILLEGAL_ERASE_ARGUMENT 。

操作 deflagment 没有任何参数。它只是将所有内存块向前依次(编号小的地方)挪动直到它们紧挨在一起。(不改变它们的顺序)

你将用连续的正整数(1,2,...)作为每一个内存块的编号。比如,第i次分配的内存块编号为i。你的任务是依次输出所有 alloc 指令的返回值,以及所有执行失败的 erase 指令的返回值。 输入输出格式 输入格式

输入文件的第一行包括两个正整数 t 和 m 。 t 表示操作次数, m 表示内存大小(为m字节)。接下来的t行为每一次的命令。命令有以下三种:alloc 命令,后接一个整数 n ; erase 命令,后接一个整数 x ; defragment 命令。 输出格式

输出文件的每一行依次为每次执行的 alloc 函数的返回值或执行失败的 erase 函数返回的 ILLEGAL_ERASE_ARGUMENT 。

translated by 星烁晶熠辉

输入输出样例

输入 #1

6 10
alloc 5
alloc 3
erase 1
alloc 6
defragment
alloc 6

输出 #1

1
2
NULL
3

题解:简单模拟,坑点:没考虑x==0的情况,呜呜呜,坑死了一直在wrong第42个测试点!!!

if(k>=ans||k<=0){
				cout<<"ILLEGAL_ERASE_ARGUMENT"<<endl;continue;
			}

AC代码:

#include<iostream>
#include<string>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int a[1000],c[1000];
int main(){
	int t,m;
	scanf("%d%d",&t,&m);
	int num=0;
	int ans=1;
	while(t--){
		string str;int k;
		cin>>str;
		if(str=="alloc"){
			cin>>k;
			int num=0;
			for(int i=1;i<=m;i++){
				if(a[i]==0){
					num++;
					if(num==k){
						for(int j=i;j>=i-k+1;j--){
							a[j]=ans;
						}
						break;
					}
				}
				else num=0;
			}
			if(num==k){
				cout<<ans<<endl;ans++;
			}
			else cout<<"NULL"<<endl;
		}
		else if(str=="erase"){
			cin>>k;
			if(k>=ans||k<=0){
				cout<<"ILLEGAL_ERASE_ARGUMENT"<<endl;continue;
			}
			int word=0;
			for(int i=1;i<=m;i++){
				if(a[i]==k){
					a[i]=0;word=1;
				}
			}
			if(word==0) cout<<"ILLEGAL_ERASE_ARGUMENT"<<endl;
		}
		else if(str=="defragment"){
			int y=1;
			memset(c,0,sizeof(c));
			for(int i=1;i<=m;i++){
				if(a[i]!=0){
					c[y++]=a[i];
				}
			}
			memset(a,0,sizeof(a));
			for(int i=1;i<=m;i++){
				if(c[i]!=0) a[i]=c[i];
			}
		}
	}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瘾ิۣۖิۣۖิۣۖิꦿ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值