郑州大学“战役杯”系列

本文介绍了一个关于疫情期间寝室买饭分摊的算法,通过抽签决定买饭人并记录每顿饭的支出,最后计算出每个人在饭钱上的收支情况。输出每个室友之间的债务关系。

郑州大学“战役杯”第一次比赛题解

我的账本

当前疫情防控形势严峻,学校为了减少同学们因为吃饭造成的聚集,规定一个寝室每次派个代表出去买饭,小W寝室的6人(编号1-6)决定每次抽签派一个人去买6份同样的套餐。但是每次买完饭后立刻转账又比较麻烦,于是他们约定每次去买饭的人先垫付,等疫情结束后再统一结算。

现在给你宿舍封闭管理期间的n顿饭中每次买饭人的序号和每份饭的单价,问疫情结束后每个人关于饭钱的收支状况?

输入格式

第一行一个正整数n,表示有n顿饭
下面n行,第i行两个正整数x,y表示第i顿饭由x去买饭,每份饭单价y元。

输出格式

一行六个整数表示每个人欠别人的钱或者别人欠他的钱。
如果他欠了别人钱,输出负数。
如果别人欠他的钱,输出正数 。

输入样例

3
1 5
2 10
3 5

输出样例

10 40 10 -20 -20 -20

注意行末不能有多余空格

样例解释

1号欠2号5元,不欠3号,4号、5号、6号各欠1号5元,故1号输出10
1号、3号欠2号5元,4号、5号、6号各欠2号10元,故2号输出40
3号与1号同理
4号欠1号5元,欠2号10元,欠3号5元,故4号为-20
5号、6号与4号同理

数据范围与提示

1≤n≤21
1≤x≤6
4≤y≤15

源代码

map对应存储 

#include <iostream>
#include <map>//map容器对应存储 
using namespace std;
map<int,int> NUM;
int main()
{
	//依次存储1号-6号室友的钱钱状况 
    NUM[1]=0;
    NUM[2]=0;
    NUM[3]=0;
    NUM[4]=0;
    NUM[5]=0;
    NUM[6]=0;
    int n;
    cin>>n;
    while(n--)
    {
        int num,money;//输入对应号码和钱钱 
        cin>>num>>money;
        //当某个大怨种买饭时,其与室友除了他本身都欠他一顿饭钱 
        for(int i = 1;i <= 6;i ++ )
        {
            if(i==num)NUM[i]+=money*5;//加上大怨种的所应收的欠款 
            else NUM[i]-=money;//其余室友加上所欠钱钱(负数) 
        }
    }
    //从1号-6号依次输出每个人的钱钱状况 
    for(int i = 1;i <= 6;i ++ )
    {
        if(i==1)cout<<NUM[i];
        else cout<<' '<<NUM[i];
    }
    //注意格式的调整即末尾无空格 
    return 0;
}

核酸检测扫码

受疫情影响,小明同学现在每天需要下楼进行核酸检测。检测时,需要先用郑好办 APP 扫描二维码并填写个人信息以便统计核酸检测结果。

小明对于二维码的构造很是好奇。据了解,二维码中的黑白可以用来表示二进制中的 0/1 。且二维码的左上角,右上角,左下角有三个形态固定的特殊方阵,用做扫码时的位置标定。通过确定这三个特殊方阵的位置,进而确定整个二维码图形在照片中的位置。除了这三个特殊方阵外,其他位置的 0/1 取值由特定方法产生,表示扫描二维码后的交互动作内容。

小明现在重点关注二维码图像中的特殊方阵,想定位仅有的三个特殊方阵。为了简化问题,你可以将二维码视为n∗m的 01 方阵,将用于标定的特殊方阵视为 8×8 的方阵,其形态如下:

11111111
10000001
10111101
10111101
10111101
10111101
10000001
11111111

现在为了安全起见,二维码标定用的三个特殊矩阵不再位于原方阵的三个角上,而是随机的分布在原方阵内(仍然保证特殊方阵之间不会相互重叠),请你找出这三个特殊方阵的位置(每个特殊方阵左上角的坐标)。

输入格式

第一行n m,表示二维码对应01矩阵的大小(0<n,m≤1000)
第二行起,给出n行m列的01矩阵

输出格式

输出共 3 行,每行两个整数,分别代表一个特殊方阵左上角所位于的行编号和列编号(行编号从上向下数分别是 0, 1, 2, 3, ...;列编号从左向右数分别是 0, 1, 2, 3, ...)。三组坐标将行编号作为第一关键字,列编号作为第二关键字升序排序后输出。

输入样例

20 20
11111111100111111111
10000001011010000001
10111101111110111101
10111101111110111101
10111101111110111101
10111101000010111101
10000001101110000001
11111111001111111111
11111000110000010111
11110000011100010010
00111011000101011101
00110011010001110001
11111111100010100000
10000001110101001101
10111101010100000101
10111101010111100000
10111101000011111001
10111101001111001001
10000001111100000011
11111111110110001001

输出样例

0 0
0 12
12 0

源代码 

 图解

即遍历元素周围四个元素模块的右,下,和右下 

#include <iostream>
#include <vector>//动态数组存储解 
#include <algorithm>//调用sort函数用于动态结构体数组排序 
using namespace std;
struct idx//结构体存储解的坐标 
{
	int x,y;
};
vector<idx> A;//开辟动态数组 
const int N = 1000+10;
char g[N][N];//创建二维字符用于储存 
int cmp(struct idx &A,struct idx &B)//自定义cmp函数来对于sort排序依据重定义 
{
	if(A.x!=B.x)return A.x<B.x;//首先按照行升序排 
	else if(A.y!=B.y)return A.y<B.y;//行相同按照列升序排 
}
int main()
{
	//对于图进行存储 
    int n,m;
    cin>>n>>m;
    for(int i = 0;i < n;i ++ )
    {
		for(int j = 0;j < m;j ++ )
		{
			cin>>g[i][j];
		}
	}
	//遍历图 
	for(int i = 0;i < n;i ++ )
	{
		for(int j = 0;j < m;j ++ )
		{
			//我们所要查找的是图中某个元素的右、下,右下元素块是否符合规则 
			if(g[i][j]=='1'&&g[i+1][j]=='1'&&g[i][j+1]=='1'&&g[i+1][j+1]=='0')
			{
				//若符合规则则查其右面的四个元素是否符合 
				if(g[i][j+7]=='1'&&g[i][j+6]=='1'&&g[i+1][j+7]=='1'&&g[i+1][j+6]=='0')
				{
					//若符合规则则查其下面的四个元素是否符合规则 
					if(g[i+7][j]=='1'&&g[i+7][j+1]=='1'&&g[i+6][j]=='1'&&g[i+6][j+1]=='0')
					{
						//若符合规则则查其右下的四个元素是否符合规则 
						if(g[i+7][j+7]=='1'&&g[i+7][j+6]=='1'&&g[i+6][j+7]=='1'&&g[i+6][j+6]=='0')
						{
							//存储解 
							A.push_back({i,j});
						}
					}
				}
			}
		}
	}
	//对于解进行排序 
	sort(A.begin(),A.end(),cmp);
	for(int i = 0;i < A.size();i ++ )
	{
        if(i==0)cout<<A[i].x<<' '<<A[i].y;
        else cout<<endl<<A[i].x<<' '<<A[i].y;
	}
	//注意最后一组解之后无回车 
    return 0;
}

辛苦的楼长

疫情防控期间,要尽最大努力的保障同学们饮食!楼长们正在统计订饭的人数,一共是三个园区的统计表放在了一个文档里,有一些粗心的同学没有分清园区,错误的将自己的信息填到了其他园区的统计表上。身为帮助楼长的热心同学,你需要写一个程序将所有同学分到正确的园区并统计各个园区需要准备的早饭、午饭、晚饭的份数。

输入格式

三组数据,每一组代表错误的园区的统计表。

每一组数据第一行是这个统计表上的信息数目n。
该组数据第2行到第n+1行是具体的信息,分别是:宿舍楼(格式为“园区(拼音,松:song,菊:jv,柳:liu)+楼号(数字)”中间无空格,例如“jv4”就表示菊园四号楼),宿舍号,早饭订饭数量,午饭订饭数量,晚饭订饭数量(某个寝室的信息只提交一次,不会重复)。

输出格式

三组数据,分别代表三个园区的数据状况,按照“松-菊-柳”的顺序输出。

每组数据第一行有四个数,分别是该园区实际订餐的寝室数目,该园区总共订的早餐数目,午餐数目,晚餐数目。

然后输出该园区的所有正确的订单信息,排序输出(保证楼号非递减输出,若是楼号相同的订单则按找寝室号递增输出)。

输入样例

在这里给出一组输入。例如:

4
song6 321 1 2 1
jv4 422 6 6 6
liu2 211 4 5 3
jv1 331 1 5 4
1
song2 333 6 6 6
1
jv6 612 2 3 3

输出样例

2 7 8 7
song2 333 6 6 6
song6 321 1 2 1
3 9 14 13
jv1 331 1 5 4
jv4 422 6 6 6
jv6 612 2 3 3
1 4 5 3
liu2 211 4 5 3

数据范围

楼号保证在范围[0-9],房号范围为(100~999),订餐数目总数小于1000,每个园区订餐信息不超过20条。

源代码

纯纯暴力朴素无华 

#include <iostream>
#include <vector>//动态数组用于创建动态结构体数组 
#include <algorithm>//排序 
#include <string.h>//查找字符子串 
using namespace std;
struct PLACE
{
	string name;//宿舍楼名 
	int num;//寝室号 
	int bre;//早餐 
	int lun;//中餐 
	int din;//晚餐 
};
vector<PLACE> A;//存松 
vector<PLACE> B;//存柳 
vector<PLACE> C;//存菊 
int cmp(struct PLACE &X,struct PLACE &Y)//自定义重置sort排序函数 
{
	if(X.name!=Y.name)return X.name<Y.name;//首先按照园区楼号递增 
	else if(X.num!=Y.num)return X.num<Y.num;//其次按照寝室号递增 
}
int sum1bre=0,sum1lun=0,sum1din=0;//松早中晚餐总数 
int sum2bre=0,sum2lun=0,sum2din=0;//柳早中晚餐总数
int sum3bre=0,sum3lun=0,sum3din=0;//菊早中晚餐总数 
int main()
{
	int n;
	//第一次 
	cin>>n;
	while(n--)
	{
		string name;
		int num;
		int bre;
		int lun;
		int din;
		cin>>name>>num>>bre>>lun>>din;
		if(name.find("song")!=-1)//若属于松 
		{
			A.push_back({name,num,bre,lun,din});//存入 
			//早中晚餐累加求和 
			sum1bre+=bre;
			sum1lun+=lun;
			sum1din+=din;
		}
		else if(name.find("jv")!=-1)//若属于柳 
		{
			B.push_back({name,num,bre,lun,din}); 
			//早中晚餐累加求和
			sum2bre+=bre;
			sum2lun+=lun;
			sum2din+=din;
		}
		else if(name.find("liu")!=-1)//若属于菊 
		{
			C.push_back({name,num,bre,lun,din});
			//早中晚餐累加求和
			sum3bre+=bre;
			sum3lun+=lun;
			sum3din+=din;
		}
	}
	cin>>n;
	while(n--)
	{
		string name;
		int num;
		int bre;
		int lun;
		int din;
		cin>>name>>num>>bre>>lun>>din;
		if(name.find("song")!=-1)
		{
			A.push_back({name,num,bre,lun,din});//若属于松  
			//早中晚餐累加求和
			sum1bre+=bre;
			sum1lun+=lun;
			sum1din+=din;
		}
		else if(name.find("jv")!=-1)
		{
			B.push_back({name,num,bre,lun,din});//若属于柳 
			//早中晚餐累加求和
			sum2bre+=bre;
			sum2lun+=lun;
			sum2din+=din;
		}
		else if(name.find("liu")!=-1)
		{
			C.push_back({name,num,bre,lun,din});//若属于菊
			//早中晚餐累加求和
			sum3bre+=bre;
			sum3lun+=lun;
			sum3din+=din;
		}
	}
	cin>>n;
	while(n--)
	{
		string name;
		int num;
		int bre;
		int lun;
		int din;
		cin>>name>>num>>bre>>lun>>din;
		if(name.find("song")!=-1)
		{
			A.push_back({name,num,bre,lun,din});//若属于松  
			//早中晚餐累加求和
			sum1bre+=bre;
			sum1lun+=lun;
			sum1din+=din;
		}
		else if(name.find("jv")!=-1)
		{
			B.push_back({name,num,bre,lun,din});//若属于柳 
			//早中晚餐累加求和
			sum2bre+=bre;
			sum2lun+=lun;
			sum2din+=din;
		}
		else if(name.find("liu")!=-1)
		{
			C.push_back({name,num,bre,lun,din});//若属于菊
			//早中晚餐累加求和
			sum3bre+=bre;
			sum3lun+=lun;
			sum3din+=din;
		}
	}
	//首先输出松的解的个数和早中晚餐总份数 
	cout<<A.size()<<' '<<sum1bre<<' '<<sum1lun<<' '<<sum1din<<endl;
	//对于其中数据排序 
	sort(A.begin(),A.end(),cmp);
	for(int i = 0;i < A.size();i ++ )
	{
		if(i==0)cout<<A[i].name<<' '<<A[i].num<<' '<<A[i].bre<<' '<<A[i].lun<<' '<<A[i].din;
		else if(i==A.size()-1)cout<<endl<<A[i].name<<' '<<A[i].num<<' '<<A[i].bre<<' '<<A[i].lun<<' '<<A[i].din<<endl;
		else cout<<endl<<A[i].name<<' '<<A[i].num<<' '<<A[i].bre<<' '<<A[i].lun<<' '<<A[i].din;
	}
	//首先输出柳的解的个数和早中晚餐总份数 
	cout<<B.size()<<' '<<sum2bre<<' '<<sum2lun<<' '<<sum2din<<endl;
	//对于其中数据排序 
	sort(B.begin(),B.end(),cmp);
	for(int i = 0;i < B.size();i ++ )
	{
		if(i==0)cout<<B[i].name<<' '<<B[i].num<<' '<<B[i].bre<<' '<<B[i].lun<<' '<<B[i].din;
		else if(i==B.size()-1)cout<<endl<<B[i].name<<' '<<B[i].num<<' '<<B[i].bre<<' '<<B[i].lun<<' '<<B[i].din<<endl;
		else cout<<endl<<B[i].name<<' '<<B[i].num<<' '<<B[i].bre<<' '<<B[i].lun<<' '<<B[i].din;
	}
	//首先输出菊的解的个数和早中晚餐总份数 
	cout<<C.size()<<' '<<sum3bre<<' '<<sum3lun<<' '<<sum3din<<endl;
	//对于其中数据排序 
	sort(C.begin(),C.end(),cmp);
	for(int i = 0;i < C.size();i ++ )
	{
		if(i==0)cout<<C[i].name<<' '<<C[i].num<<' '<<C[i].bre<<' '<<C[i].lun<<' '<<C[i].din;
		else if(i==C.size()-1)cout<<endl<<C[i].name<<' '<<C[i].num<<' '<<C[i].bre<<' '<<C[i].lun<<' '<<C[i].din;
		else cout<<endl<<C[i].name<<' '<<C[i].num<<' '<<C[i].bre<<' '<<C[i].lun<<' '<<C[i].din;
	}
	//注意对于输出格式进行调整	
	return 0;
}

等待做核酸

最近新一轮新冠疫情来势汹汹,形势极为严峻,为了保障全体师生的安全,在校师生需要每天做核酸。每天医护人员到达的时间都是不固定的,为了简化问题,假设医护人员到达的时间是整分钟(如10:05:00),并且知道医护人员到达时间的区间,医护人员在这个区间的任意时刻到达的概率相同,核酸检测结束的时间为23:59。在校学生妙酱每天都会按时做核酸,并且妙酱出来做核酸的时间也为整分钟,妙酱想知道自己等多久可以做核酸。由于开始做核酸的时间是不固定的,请你求出妙酱做核酸等待时间(分钟)的期望,忽略妙酱排队等待的时间。

输入格式

第一行医护人员到达时间的区间(hh:mm-hh:mm)。

第二行cc出来做核酸的时间(hh:mm)。

输入的时间均在一天内。

输出格式

等待时间(分钟)的期望值,保留两位小数。

输入样例

10:00-10:29
10:15

输出样例

3.50

源代码

这道题太老六了我真的是糊了 

#include <iostream>
using namespace std;
int main()
{
	//利用格式化读入快速得到数据 
	int h1,m1,h2,m2;
	scanf("%2d:%2d-%2d:%2d",&h1,&m1,&h2,&m2);
	int h3,m3;
	scanf("%2d:%2d",&h3,&m3);
	//化为分钟对数据进行处理 
	int st=h1*60+m1;//医生开始 
	int ed=h2*60+m2;//医生走 
	int t=h3*60+m3;//cc到的时间 
	double ans=0;//初始化 
	//总概率为1分为(ed-st+1)份 
	for(int i = 1;i <= ed-t;i ++ )
	{
		//从cc到开始直至医生走累加求和 
		ans+=i*1.0/(ed-st+1);
	}
	printf("%.2lf",ans);
	return 0;
}

郑州大学“战役杯”第二次比赛题解

公司的Logo

为了感谢河南省八六三软件有限公司对战疫杯ACM在线程序设计竞赛的大力支持,小Y决定为公司制作个logo。

logo通常要用在各种不同的场景,因此logo的尺寸必须是可变的。现给你原始的logo,以及其改变尺寸的例子,你能寻找规律并输出任意缩放后的logo图案吗?

原始logo:

### ### ###
# # #     #
### ### ###
# # # #   #
### ### ###

将其放大一倍的示例:

#### #### ####
#  # #       #
#  # #       #
#### #### ####
#  # #  #    #
#  # #  #    #
#### #### ####

其放大两倍的示例是

##### ##### #####
#   # #         #
#   # #         #
#   # #         #
##### ##### #####
#   # #   #     #
#   # #   #     #
#   # #   #     #
##### ##### #####

输入格式

输入一个整数n(0≤n≤10),表示放大的倍数。特别的,n等于0时输出原字符画。

输出格式

输出对应倍数的字符画。

输入样例

1

输出样例

#### #### ####
#  # #       #
#  # #       #
#### #### ####
#  # #  #    #
#  # #  #    #
#### #### ####

源代码

题解思路:

我们可以发现对于第0、5+2*n-1和第(5+2*n-1)/2行的团都是由三部分相同的#组成

且从列方面看在第3+n列和第(3+n)*2+1列都有一个空格出现

这三行除了这两列的空格其余均为#来填充

然后我们从其余行开始看

很清晰上半部分在第0、11+3*n-1、3+n-1、3+n-1+2列只出现了#

下半部分在第0、11+3*n-1、3+n-1、3+n-1+2、3+n-1+2+3+n-1列出现了#

所以我们可以对图进行上下部分处理

另外图的放缩的话对于行是按照5+n*2的规律放缩

对于列是按照11+3*n的规律进行放缩

暴力模拟

#include <iostream>
using namespace std;
const int N = 1000+10;//为图开辟空间
char g[N][N];//创建二维字符数组进行图的存储
int main()
{
	int n;
	cin>>n;
	int space1=3+n;//首个空格所在列数
	int space2=(3+n)*2+1;//第二个空格所在列数
	for(int i = 0;i <5+n*2;i ++ )
	{
		for(int j = 0;j < 11+3*n;j ++ )
		{
            //对于三行特殊的图案进行处理
			if(i==0||i==5+n*2-1||i==(5+2*n-1)/2)
			{
				if(j==space1||j==space2)
				{
					g[i][j]=' ';
				}
				else g[i][j]='#';
			}
			else
			{
                //对于图的上半部分处理
				if(i>=0&&i<=(5+2*n-1)/2)
				{
					if(j==0||j==11+3*n-1||j==3+n-1||j==3+n-1+2)
					{
						g[i][j]='#';
					}
					else g[i][j]=' ';
				}
				else
				{
                    //对于图的下半部分处理
					if(j==0||j==11+3*n-1||j==3+n-1||j==3+n-1+2||j==3+n-1+2+3+n-1)
					{
						g[i][j]='#';
					}
					else g[i][j]=' ';
				}
			}
		}
	}
    //对图进行逐行输出
	for(int i = 0;i <5+n*2;i ++ )
	{
		puts(g[i]);
	}
	return 0;
}

解封日期

小明所在的城市发生了疫情,实行静态化管理,小明也被关在家里,不能去上学了。

根据当地政策,连续N天没有新增病例,就可以解封。小明知道过去M(M≤N)天的每天的新增病例数,他想知道理想情况下最早什么时候可以解封。

输入格式

第一行一个日期,格式为YYYY/MM/DD。

第二行两个整数N和M,0<M≤N≤30。

之后M行,每行一个整数0≤Xi​≤100,0≤i<M,表示从今天开始,往过去数第i天的新增病例数(包括今天)。

输出格式

一行,一个日期,格式为YYYY/MM/DD,请不要有多余的空格。

输入样例

2004/10/28
4 2
1
0

输出样例

2004/11/01

源代码

首先我们创建了两个一维数组分别用来存储闰年月份天数和平年月份天数

动态数对对于每次输入的数据进行存储

从动态数对的头开始遍历,查找出现病例的那天,如果没有则将偏移量加一

最小天数加上偏移量即为所需要多少天才能解封

注意数据M>=N(避免考虑复杂),这里我的偏移量为负数

因此n加上偏移量一定是大于等于0的

所以最短解封时间一定在今天以及今天之后

所以我们可以放心的使用while对n--判断从而往后累加天数

注意在累加之前我们要先对年份进行类型判断

累加时注意月份的进位和年份的进位

#include <iostream>
#include <vector>
using namespace std;
int a[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};//平年月份天数数组
int b[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};//闰年月份天数数组
typedef pair<int,int> PII;
vector<PII> A;//动态数对
int main()
{
    //格式化输入获取当前年月日
	int year,month,day;
	scanf("%4d/%2d/%2d",&year,&month,&day);
	int n,m;
	cin>>n>>m;
	for(int i = 1;i <= m;i ++ )
	{
        //注意key的值即为偏移量的值我们直接按照下标作为偏移量存储
		int key=i-1;
		int num;
		cin>>num;
		A.push_back({key,num});//存进去
	}
	int delta=-m;//默认动态数对中的数据是没有病例出现的,此时偏移量为m
	for(int i = 0;i < A.size();i ++ )
	{
        //如果查找到了病例出现的那天
		if(A[i].second!=0)
		{
			delta=-A[i].first;//更新偏移量的值
			break;//直接跳出循环
		}
	}
	n=n+delta;//n与偏移量进行处理
	if((year%4==0&&year%100!=0)||year%400==0)//闰年
	{
		while(n--)//累加天数
		{
			day++;
			if(day>b[month])//注意月份进位
			{
				month++;
				day=1;
			}
			if(month>12)//注意年份进位
			{
				year++;
				month=1;
			}
		}
	}
	else//平年
	{
		while(n--)//累加天数
			{
				day++;
				if(day>a[month])//注意月份进位
				{
					month++;
					day=1;
				}
				if(month>12)//注意年份进位
				{
					year++;
					month=1;
				}
			}
	}
    //输出最早解封的日期
	printf("%4d/%02d/%02d",year,month,day);
	return 0;
} 

语音设备是否正常?

因疫情防控改为线上授课后,有些同学开始沉迷游戏。你的寝室有个室友最近喜欢了一款游戏:Hxxxxx Dxxxx。该游戏能够正常进行的重要前提就是所有玩家的语音输入设备都是正常的,即每个玩家需要通过麦克风与其他玩家交流。该游戏有8种角色,每人进入游戏房间时需要不重复地选择一种角色,游戏房间满8人后,房主可以正常开启本局游戏。玩家进入房间后,通常需要通过语音与其他玩家交流,以证明自己的麦克风设备是正常的。作为房主,需要时刻了解当前进入房间的其他玩家是否通过麦克风交流过,进而决定是否开启本局游戏,或者踢出没有说过话的玩家。你的室友作为房主,你能通过程序设计帮助他这个忙吗?另外,房主保证自己的设备是没问题的。

说明:该游戏中的8中角色分别为船长(Captain), 牧师(Priest),厨师(Cook),医生(Doctor),工程师(Engineer),猎人(Hunter),枪手(Gunner), 导航官(Navigator)。

后记:帮助完房主设计完这个程序后,你愈发觉得作为一个计算机专业的学生,应该去尝试编程写一个游戏赚别人钱,而不是浪费时间还花钱玩游戏。从此你一发而不可收拾,游戏编程界的一颗新星冉冉升起!

输入格式

第一行一个字符串,表示房主建立房间所选择的角色;
第二行一个正整数N,0<N≤1000,表示语音的条数;
以下N行字符串,每一行都是形如:

角色: XXX XXX XXX XX

表示哪个角色通过语音说了什么话。中间是英文冒号,每行字符串长度不超过200。

输出格式

如果所有玩家设备均正常,输出"Ready"(不包括引号);否则输出没有语音交流过的玩家角色名,每行一个(按照角色单词的字典序从小到大依次输出)。

输入样例1

Captain
10
Hunter:Hi.
Navigator:Hello, everyone
Doctor:here is the doctor.
Priest:voice test
Hunter:is my device ready?
Captain: yes
Cook:chu shi you mai
Gunner:of course
Engineer: i'm ready
Gunner: go go

输出样例1

Ready

输入样例2

Priest
7
Hunter:Hi.
Engineer: i'm ready
Navigator:Hello, everyone
Doctor:here is the doctor.
Hunter: is my device ready?
Gunner:of course
Gunner: how about the cook?

输出样例2

Captain
Cook

 源代码

map暴力方法

使用find函数查找

将未出现的职业推入动态数组当中并进行字典序排序 

#include <iostream>
#include <map>//容器暴力
#include <string.h>//find函数
#include <vector>//动态数组
#include <algorithm>//sort排序
using namespace std;
map<string,string> P;//定义map容器
vector<string> A;//定义动态数组
int main()
{
	string s;
	cin>>s;
    //首先对于房主的职业存储
	P[s]="Ready";
	int n;
	cin>>n;
	while(n--)
	{
        //依次对于八个职业进行查,查找到了则在容器中改其值为Ready
		string str;
		getline(cin,str);
		if(str.find("Captain")!=-1)
		{
			P["Captain"]="Ready";
		}
		else if(str.find("Hunter")!=-1)
		{
			P["Hunter"]="Ready";
		}
		else if(str.find("Priest")!=-1)
		{
			P["Priest"]="Ready";
		}
		else if(str.find("Cook")!=-1)
		{
			P["Cook"]="Ready";
		}
		else if(str.find("Doctor")!=-1)
		{
			P["Doctor"]="Ready";
		}
		else if(str.find("Engineer")!=-1)
		{
			P["Engineer"]="Ready";
		}
		else if(str.find("Gunner")!=-1)
		{
			P["Gunner"]="Ready";
		}
		else if(str.find("Navigator")!=-1)
		{
			P["Navigator"]="Ready";
		}
	}
    //查找八个职业哪儿个职业未出现,将未出现的职业压入动态数组当中
	if(P["Captain"]!="Ready")A.push_back("Captain");
	if(P["Hunter"]!="Ready")A.push_back("Hunter");
	if(P["Priest"]!="Ready")A.push_back("Priest");
	if(P["Cook"]!="Ready")A.push_back("Cook");
	if(P["Doctor"]!="Ready")A.push_back("Doctor");
	if(P["Engineer"]!="Ready")A.push_back("Engineer");
	if(P["Gunner"]!="Ready")A.push_back("Gunner");
	if(P["Navigator"]!="Ready")A.push_back("Navigator");
    //当动态数组中所存储元素为0即所有职业都出现时
	if(A.size()==0)cout<<"Ready";//输出准备好了
	else//当有职业未出现时
	{
		sort(A.begin(),A.end());//首先对于职业进行字典序排序
		for(int i = 0;i < A.size();i ++ )cout<<A[i]<<endl;//再依次输出未出现的职业
	}
	return 0;
}

郑州大学“战役杯”第三次比赛题解

疫情防控网格化

由于防控形势严峻,现在z市已经开始了全区域的网格化封控管理。该市的区域可以看成一个矩形,其中所有主干道都是水平或垂直的,并且贯穿整个区域。如图所示,黑色表示城区的边界,红色表示城区的主干道,其中边界和主干道宽度都为1,且不存在边界与主干道、主干道与主干道相邻的情况

为了方便网格化管理,我们定义网格单元是由城区边界或主干道围成的区域,且任意网格单元内不能包含主干道。上图中,该城区共被分割成了16个网格单元。

现在给出该区域的地图,需要你统计出该城区划分出了多少个网格单元,以方便安排医务人员和应急物资。

在计算机中,图像的本质就是二维的矩阵。为了方便处理,我们将上述图像中城区边界及里面的内容转化为了二维字符矩阵,详细见输入格式描述。

输入格式

第一行输入两个整数n,m(3≤n,m≤100)
其后n行,每行m个字符,字符有'*'和'#'两种。'*'代表城区边界或主干道,'#'代表网格单元内区域。

输出格式

输出一行一个整数,代表地图中的网格单元个数。

输入样例

3 7
*******
*##*##*
*******

输出样例

2

源代码

传染:即为当某个元素为#时,其相邻的#的位置均被打上标记,即对于连着的#只计算一个解 

#include <iostream>
using namespace std;
const int N = 1000+10;
char g[N][N];//存图
int a[N][N]={0};//标记数组
int main()
{
    int ans=0;
    int n,m;
    cin>>n>>m;
    for(int i = 0;i < n;i ++ )
    {
        for(int j = 0;j < m;j ++ )
        {
            cin>>g[i][j];
        }
    }
    for(int i = 0;i < n;i ++ )
    {
        for(int j = 0;j < m;j ++ )
        {
            if(g[i][j]=='#')//如果查到元素为#
            {
                if(a[i+1][j]==0&&a[i-1][j]==0&&a[i][j+1]==0&&a[i][j-1]==0)//且该元素周围无标记
                {
                    a[i][j]=1;//标记该位置
                    ans++;//答案加一
                }
                else a[i][j]=1;//若周围有标记则“传染”
            }
        }
    }
    cout<<ans;
    return 0;
}

子区域计数

由于防控形势严峻,现在z市已经开始了全区域的网格化封控管理。该市的区域可以看成一个矩形,其中所有主干道都是水平或垂直的,并且贯穿整个区域。如图所示,黑色表示城区的边界,红色表示城区的主干道。其中边界和主干道宽度都为1,且不存在边界与主干道、主干道与主干道相邻的情况。

为了方便网格化管理,我们定义网格单元是由城区边界或主干道围成的区域,且任意网格单元内不能包含主干道。上图中,该城区共被分割成了16个网格单元。

同时,网格化管理的本质思想是“分治”,不同的划分粒度对于管理效率会产生深远的影响。所以,这次W同学思考的不仅仅是网格单元,而是子网格。

子网格的定义为:子网格也是一个矩形,且子网格矩形4个角的对应点都位于边界与边界、边界与主干道、主干道与主干道的交点上。我们认为两个子网格是相同的,当且仅当两个子网格的4个角对应点全部重合。根据这个定义,我们可以知道,任意的网格单元也是一种子网格,整个城区的矩形也是一种特殊的子网格。

同样给出上述的图像,你能否帮小W计算下,有多少种可能的子网格?

输入格式

第一行输入两个整数n,m(3≤n,m≤100)
其后n行,每行m个字符,字符有'*'和'#'两种。'*'代表城区边界或主干道,'#'代表网格单元内区域。

输出格式

输出一行一个整数,代表符合条件不同子网格的个数。

输入样例

3 7
*******
*##*##*
*******

 源代码

 标记数组处理以后对应关系

#include <iostream>
using namespace std;
const int N = 1000+10;
char g[N][N];//存图 
int a[N][N]={0};//标记数组 
int ans=0;
int n,m;
int main()
{
    cin>>n>>m;
    for(int i = 0;i < n;i ++ )
    {
        for(int j = 0;j < m;j ++ )
        {
            cin>>g[i][j];//对图进行输入时 
            if(g[i][j]=='#')//若此元素为# 
            {
				for(int k = 0;k < n;k ++ )a[k][j]=1;//该元素所在行打标记 
				for(int l = 0;l < m;l ++ )a[i][l]=1;//该元素所在列打标记 
			}
        }
    }
    //开始查为*且未被标记的 
    for(int i = 0;i < n;i ++ )
    {
        for(int j = 0;j < m;j ++ )
        {
            if(a[i][j]==0&&g[i][j]=='*')
            {
				for(int k = i;k < n;k ++ )
				{
					for(int l = j;l < m;l ++ )
					{
						if(k!=i&&l!=j&&g[k][l]=='*'&&a[k][l]==0)ans++;
						//如果查到的*不同行不同列且未被标记则为一个矩形的解 
					}
				}
			}
        }
    }
    cout<<ans;
    return 0;
}

怀旧的思考挑战

疫情来了,柴刘青山在寝室关着非常无聊,和室友一起玩跑跑卡丁车这款老游戏。

这款游戏有一个模式叫做组队竞速,每局8个人,分为两队,最终比拼哪队总分更高。

第一名冲线得到8分,第二名得到7分,以此类推,第八名得到1分。

柴刘青山好奇自己队伍在某一局游戏中是否能得到某个总分,如果可以,有多少种排名情况可以达成该总分?

后记:柴刘青山和室友们寻求过短暂的放松后,决定还是在学业上开启“竞速模式”,约定共同努力学习,参加“战疫杯”!

输入格式

第一行一个正整数n,表示猜想的n总分。 0≤n≤10000

输出格式

如果可以达成,输出一个正整数x,代表有多少种排名情况。
如果不能达成,输出NO。

输入样例

25

输出样例

1

样例解释1

柴刘青山的队伍需要取得1、2、3、5名,对应8+7+6+4=25。有且仅有这一种情况。

源代码

从高到低枚举即可,注意在枚举的时候我们是要尽量满足那个解的情况,因此我们要从大到小进行枚举,且枚举的时候每个内层变量是外层变量的后一位,因此我们可以避免对于枚举的四个数进行判断是否两两,节省大量程序运算时间的同时也能够保证四个数各不相同

#include <iostream>
using namespace std;
int main()
{
    int num;
    cin>>num;
    int ans=0;
    for(int i = 8;i >= 1;i -- )
    {
        for(int j = i-1;j >= 1;j -- )
        {
            for(int k = j-1;k >= 1;k -- )
            {
                for(int l = k-1;l >= 1;l -- )
                {
                    if(i+j+k+l==num)ans++;
                }
            }
        }
    }
    if(ans==0)cout<<"NO";
    else cout<<ans;
    return 0;
}

郑州大学“战役杯”第四次比赛题解

时空密接 

在抗击疫情的过程中,我们需要清楚确定密接,而感染者的整个运动过程中和他位置重合的人都将被当作密切接触者,现在就请你设计一个算法计算两个人的轨迹是否有时空密接。

为了简化问题我们把场景当成一个二维坐标系,每个人看作坐标系上的一个整数点,在每一个时刻会原地不动或向上下左右移动一格,我们认为两个人只要在某一时刻出现在了同一个网格中就是时空密接。

输入格式

第一行包含五个用空格隔开的正整数x1​,y1​,x2​,y2​(−109≤x1​,y1​,x2​,y2​≤109),t(1≤t≤100),分别代表两个人在0时刻所处的位置,以及接下来的t时刻中的移动路径。

第二行和第三行都是一个长度为t的字符串,分别代表两人在每一时刻的移动轨迹,字符串由大写字母W,S,A,D,O组成,分别代表上下左右移动一格与停止不动,即坐标由(x,y)改变为(x,y+1),(x,y−1),(x−1,y),(x+1,y),(x,y)。

输出格式

如果两人存在时空密接就输出'yes',否则则输出'no'(不含引号,且区分大小写)。

输入样例

1 1 2 2 4
DDDO
DSDD

输出样例

yes

样例解释

两人的坐标分别为:

(1,1)→(2,1)→(3,1)→(4,1)→(4,1)

(2,2)→(3,2)→(3,1)→(4,1)→(5,1)

因此两人在第2、3时刻在同一位置,属于时空密接。

源代码 

今天心态炸裂了家人们第一题因为特判WA了几次 

注意特判可能刚开始就有时空交际 

#include <iostream>
using namespace std;
int main()
{
	int x1,y1,x2,y2,t;
	cin>>x1>>y1>>x2>>y2>>t;
	string a,b;
	cin>>a>>b;
    int flag=0;
	for(int i = 0;i < t;i ++ )
	{
        if(x1==x2&&y1==y2)
		{
			flag=1;
			break;
		}
		switch(a[i])
		{
			case 'A':
				x1=x1-1;
				break;
			case 'W':
				y1=y1+1;
				break;
			case 'D':
				x1=x1+1;
				break;
			case 'S':
				y1=y1-1;
				break;
			case 'O':
				break;
		}
		switch(b[i])
		{
			case 'A':
				x2=x2-1;
				break;
			case 'W':
				y2=y2+1;
				break;
			case 'D':
				x2=x2+1;
				break;
			case 'S':
				y2=y2-1;
				break;
			case 'O':
				break;
		}
	} 
	if(flag==0)cout<<"no";
    else if(flag==1)cout<<"yes";
	return 0;
}

今晚吃鸡

777777777Plus和SW2000正在游玩一款fps(第一人称射击类)游戏,在游戏中777777777Plus和SW2000需要瞄准射击,当系统判定到击中头部,身体,和四肢时会造成不同的伤害。当击中头部时,会造成100点伤害;当击中胸背部时,会造成30点伤害,当击中四肢时,会造成10点伤害。当血量小于等于0时,游戏结束,血量不为0的一方获胜。

同时该游戏有防具设计,包括头盔(保护头部)和护甲(保护胸背部)。当玩家穿着防具时,对该部位的攻击会由扣除血量改为扣除防具的耐久度。当防具耐久度降低到0时将会破碎失去伤害抵挡效果。

换言之,如果防具当前耐久为x,收到的攻击为y,当x>y时,防具的耐久变为x−y,不会破碎。当x≤y时,防具会破碎,且此次攻击不再扣除玩家血量。

现在,给出777777777Plus和SW2000游戏的记录,你能否算出是谁在游戏中获胜了?

输入格式

第一行输入三个整数a1,b1,c1(1≤a1≤100,0≤b1,c1≤100),分别表示777777777Plus的剩余血量,护甲耐久度,头盔耐久度。

第二行输入三个整数a2,b2,c2(1≤a2≤100,0≤b2,c2≤100),分别表示SW2000的剩余血量,护甲耐久度,头盔耐久度。

第三行一个n(1≤n≤1000)代表游戏记录条数。

其后n行,每行两个字符串s,t。其中当s是"777777777Plus"(不带引号)时,代表777777777Plus受到了攻击,反之当s是"SW2000"(不带引号)时,代表SW2000受到了攻击。
当t是"head"(不带引号)时,代表头部受到攻击,当t是"body"(不带引号)时,代表胸背部受到攻击,当t是"limbs"(不带引号)时,代表四肢受到攻击。

数据保证不存在玩家血量小于等于0后继续攻击的情况。

输出格式

输出一行一个字符串,"777777777Plus"或者"SW2000",代表获胜玩家。输出时不需要带引号。

输入样例

1 1 1
100 0 0
4
777777777Plus head
SW2000 body
777777777Plus body
SW2000 head

输出样例

777777777Plus

源代码

心态继续炸裂b错写成aWA了十几次 

#include <iostream>
using namespace std;
int main()
{
	//一定要注意讨论的时候a和b的区别,我wa了快十次一看是b错写成了a 
	int a1,b1,c1;
	cin>>a1>>b1>>c1;
	int a2,b2,c2;
	cin>>a2>>b2>>c2;
	int t;
	cin>>t;
	string human;
	string idx;
	while(t--)
	{
		//开头无特判 
		cin>>human>>idx;
		if(human=="777777777Plus")
		{
			//只要装备不烂就疯狂抗 
			if(idx=="head")//爆头 
			{
				if(c1>0)c1-=100;
				else a1-=100;
			} 
			else if(idx=="body")//打腰子 
			{
				if(b1>0)b1-=30;
				else a1-=30;
			}
			else a1-=10;//打胳膊腿 
		} 
		else
		{
			//只要装备不烂就疯狂抗
			if(idx=="head")//爆头 
			{
				if(c2>0)c2-=100;
				else a2-=100;
			} 
			else if(idx=="body")//打腰子
			{
				if(b2>0)b2-=30;
				else a2-=30;
			} 
			else a2-=10;//打胳膊腿
		}
		//哪个大怨种被射死了活着的就是赢家 
		if(a1<=0)
		{
			cout<<"SW2000";
			break;
		} 
		else if(a2<=0)
		{
			cout<<"777777777Plus";
			break;
		}
	}
	return 0;
}

核酸排队

在疫情到来的时候,做核酸成了大多数同学们的日常。做核酸也是需要时间的,而且在一个核酸检测点做核酸的人数往往很多,等待时间有时候会比较长。

在一个核酸检测点基本都安排有两个队列(默认两个队列的长度都为无限大):

  • 扫码队列:在该队列中,我们等待志愿者扫码录入核酸检测信息,志愿者每扫一个同学的码需要x单位时间。
  • 核酸队列:在该队列中,我们等待医生为我们做核酸,每个同学做核酸需要y单位时间。

一位同学做核酸的过程可以认为是先到达扫码队列等待志愿者扫码录入信息,录入信息之后到达核酸队列等待做核酸。一个志愿者一次只能处理一个同学的扫码,一个医生一次只能对一位同学进行核酸检测。

小王深深体会到了医生们的辛苦,他希望通过计算同学们等待做核酸的时间,以此平衡好同学们做核酸、学习和生活的时间。

假设核酸检测点只有一个志愿者和一个医生。已知有n个同学,第i个同学到达核酸检测点(即到达扫码队列)的时间为ti​(数据保证到达扫码队列的时间是升序的,且各不相同),求编程计算第i个同学做核酸耗费的时间wi​。

本题认为耗费时间为从到达扫码队列到完成做核酸的时间

输入格式

一共三行。

第一行为一个整数n(1≤n≤105)。

第二行为两个整数x,y(1≤x,y≤105)

第三行为n个整数t1​,t2​,t3​,...,tn−1​,tn​(1≤ti​≤109)

输出格式

在一行输出n个核酸检测等待时间w1​,w2​,w3​,...,wn​

输入样例

3
2 3
3 5 6

输出样例

在这里给出相应的输出。例如:

5 6 8

源代码

数列这东西我不太熟还是参考的一位大佬的思路肝出来了 

#include<iostream>
#include<queue>//数列 
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PII;
queue<PII> A,B;//创建数对队列 
int main()
{
	//首先数据较大,开优化 
	ios::sync_with_stdio(false);
	cin.tie(0);
	//进行数据输入 
	ll n;
    cin>>n;
	ll x,y;
	cin>>x>>y;
    while(n--)
    {
    	//对于每个同学到达的时间进行输入 
    	ll num;
        cin>>num;
        A.push({num,0});//存的first是该同学到达的时间,second是该同学等待的时间 
    }
    ll del=A.front().first;//默认偏移量为首个同学到达的时间 
    //首先对于A数对数列进行处理,也就是扫码队列 
    while(!A.empty())//当该队列全部成员为处理完毕时 
    {
        if (del>=A.front().first)//如果偏移量比该同学的来到时间长也就是该同学要等待扫码的情况 
        {
            del+=x;//偏移量加上扫码时间即为来到核酸队列的时间 
            auto t = A.front();//定义临时数对 
            t.second = del-t.first;//second存的是该学生等待的时间和扫码的时间的和也就是偏移量与该同学到来时间的差值 
            t.first = del;//first为该同学来到核酸队列的时间 
            B.push(t);//推入核酸队列 
            A.pop();//弹出扫码队列 
        }
        else//如果偏移量比该同学来到的时间短也就是该同学一来就能够扫码,那么等待时间为0 
        {
            auto t=A.front();//定义临时数对 
            del=t.first+x;//该同学来到扫码队列的时间加上扫码的时间为来到核酸队列的时间 
            t.second=x;//second存的是该学生所用的时间之和在此仅仅为扫码的时间 
            t.first=del;//该学生来到核酸队列的时间 
            B.push(t);//推入 
            A.pop();//弹出 
        }
    }
    del = B.front().first;//偏移量更新为首位同学来到核酸队列的时间 
    while (!B.empty())//如果队列中的数对未处理完毕 
    {
        if(del>=B.front().first)//如果偏移量大于该同学来到核酸队列的时间也就等价于该同学要等待一段时间 
        {
            del+=y;//做完核酸之后+偏移量的和 
            auto t=B.front();//定义临时数对 
            B.pop();//弹出 
            cout<<t.second+(del-t.first);//输出second(扫码所需要的总时间)加上更新完的偏移量减去first即为核酸用的总时间 
            if (!B.empty())cout<< " ";//如果此时队列还有元素注意输出一个空格 
        }
        else//此时偏移量小于该同学来到核酸队列的时间也就是等待时间为0 
        {
            auto t = B.front();//定义临时数对 
            B.pop();//弹出 
            del=t.first+y;//偏移量更新 
            cout<<t.second+y;//该同学所用的总时间等于second(扫码所需要的总时间)+y(做核算所需要的总时间) 
            if(!B.empty())cout<<" ";//如果此时队列还有元素注意输出一个空格 
        }
    }
    return 0;
}

 

评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

计科土狗

谢谢家人们

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

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

打赏作者

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

抵扣说明:

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

余额充值