CCF计算机职业资格认证考试

[待更

CCF 202009-1

试题编号: 202009-1
试题名称: 称检测点查询
时间限制: 1.0s
内存限制: 256.0MB

题目背景

2020 年 6 月 8 日,国务院联防联控机制发布《关于加快推进新冠病毒核酸检测的实施意见》,提出对“密切接触者”等八类重点人群“应检尽检”,其他人群“愿检尽检”。

问题描述

某市设有 n 个核酸检测点,编号从 1 到 n,其中 i 号检测点的位置可以表示为一个平面整数坐标 (xi,yi)。

为方便预约核酸检测,请根据市民所在位置 (X,Y),查询距其最近的三个检测点。
多个检测点距离相同时,编号较小的视为更近。

输入格式

输入共 n+1 行。

第一行包含用空格分隔的三个整数 n、X 和 Y,表示检测点总数和市民所在位置。

第二行到第 n+1 行依次输入 n 个检测点的坐标。第 i+1 行(1≤i≤n)包含用空格分隔的两个整数 xi 和 yi,表示 i 号检测点所在位置。

输出格式

输出共三行,按距离从近到远,依次输出距离该市民最近的三个检测点编号。

样例输入1

3 2 2
2 2
2 3
2 4

Data

样例输出1

1
2
3

Data

样例输入2

5 0 1
-1 0
0 0
1 0
0 2
-1 2

Data

样例输出2

2
4
1

分析:

保存到各个检测点距离,排个序,按序取出3个结果。(可以边输入边处理,结果集只保留3个距离,以期减小空间开销,而且不需要再排序,但写起来会麻烦一些。)

注意:

CCF的编译环境似乎不支持c++的pair,需要自定义结构体和compare函数。

c++版(compile error但仍有借鉴意义,vs2019本地测试通过)
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;

int main()
{
	int num, x, y;
	cin >> num >> x >> y;
	vector<pair<int, double> > dist;  //first:index, second:distance
	int xi, yi;
	for (int i = 1; i <= num; ++i) {
		cin >> xi >> yi;
		dist.emplace_back(make_pair(i, pow(x - xi, 2) + pow(y - yi, 2)));
	}
	sort(dist.begin(), dist.end(), [](const pair<int, double>p1, const pair<int, double>p2) {
		return p1.second < p2.second; });//order by desc
	dist.erase(dist.begin() + 3, dist.end());
	for (const auto& d : dist)
		cout << d.first << endl;
	return 0;
}
python版
n,x,y = map(int,input().split())
dist = []
for i in range(1,n+1):
    xi,yi = map(int,input().split())
    dist.append([(x-xi)**2+(y-yi)**2,i])
dist.sort()  #按第一项排序,若第一项相同按第二项排序
for i in range(3):
    print(dist[i][1])

CCF 202009-2

试题编号: 202009-2
试题名称: 风险人群筛查
时间限制: 1.0s
内存限制: 256.0MB

题目背景

某地疫情爆发后,出于“应检尽检”的原则,我们想要通知所有近期经过该高危区域的居民参与核酸检测。

问题描述

想要找出经过高危区域的居民,分析位置记录是一种简单有效的方法。

具体来说,一位居民的位置记录包含 t 个平面坐标 (x1,y1),(x2,y2),⋯,(xt,yt),其中 (xi,yi) 表示该居民 i 时刻所在位置。
高危区域则可以抽象为一个矩形区域(含边界),左下角和右上角的坐标分别为 (xl,yd) 和 (xr,yu),满足 xl<xr 且 yd<yu。

考虑某位居民的位置记录,如果其中某个坐标位于矩形内(含边界),则说明该居民经过高危区域;进一步地,如果其中连续 k 个或更多坐标均位于矩形内(含边界),则认为该居民曾在高危区域逗留。需要注意的是,判定经过逗留时我们只关心位置记录中的 t 个坐标,而无需考虑该居民在 i 到 i+1 时刻之间位于何处。

给定高危区域的范围和 n 位居民过去 t 个时刻的位置记录,试统计其中经过高危区域的人数和曾在高危区域逗留的人数。

输入格式

输入共 n+1 行。

第一行包含用空格分隔的七个整数 n、k、t、xl、yd、xr 和 yu,含义如上文所述。

接下来 n 行,每行包含用空格分隔的 2t 个整数,按顺序表示一位居民过去 t 个时刻的位置记录 (x1,y1),(x2,y2),⋯,(xt,yt)。

输出格式

输出共两行,每行一个整数,分别表示经过高危区域的人数和曾在高危区域逗留的人数。

样例输入1

5 2 6 20 40 100 80
100 80 100 80 100 80 100 80 100 80 100 80
60 50 60 46 60 42 60 38 60 34 60 30
10 60 14 62 18 66 22 74 26 86 30 100
90 31 94 35 98 39 102 43 106 47 110 51
0 20 4 20 8 20 12 20 16 20 20 20

Data

样例输出1

3
2

Data

样例1说明

如下图红色标记所示,前三条位置记录经过了高危区域;
但第三条位置记录(图中左上曲线)只有一个时刻位于高危区域内,不满足逗留条件。

p2.png

样例输入2

1 3 8 0 0 10 10
-1 -1 0 0 0 0 -1 -1 0 0 -1 -1 0 0 0 0

Data

样例输出2

1
0

Data

样例2说明

该位置记录经过了高危区域,但最多只有连续两个时刻位于其中,不满足逗留条件。

python版
n,k,t,xl,yd,xr,yu = map(int,input().split())
res = [0,0]
for i in range(n):
    cnt = 0
    flag = False
    pos = list(map(int,input().split()))  #每位的位置信息
    for i in range(0,t*2,2):
        if(xl <= pos[i] <= xr and yd <= pos[i+1] <= yu):  #py支持链式比较
            cnt += 1
            if(cnt >= k): #满足逗留
                res[1] += 1
                break
            if(not flag):  #满足经过
               flag = True
               res[0] += 1
        else: cnt = 0  #离开高危区域
for i in range(2):
    print(res[i])

CCF 202006-1

img

img

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	int n, m, x, y;
	char type;
	vector<pair<int,int> > A, B;
	cin >> n >> m;
	while (n--) {
		cin >> x >> y >> type;
		if (type == 'A')  A.push_back(make_pair(x, y));
		else B.push_back(make_pair(x, y));
	}
	int a, b, c;
	while (m--) {
		cin >> a >> b >> c;
		bool res = true;
		bool flag = (a + b * A.front().first + c * A.front().second ) > 0 ? true : false;  //A组第一个点的位置在左侧或右侧
		for(int i = 1;i<A.size();++i)
			if ((a + b * A[i].first + c * A[i].second > 0) != flag) {  //A组其他点是否与第一个点同侧
				res = false;
				break;
			}
		if (res) {  //若A组所有点同侧
			for(int i = 0;i < B.size();++i)
				if ((a + b * B[i].first + c * B[i].second > 0) == flag) {  //B组是否所有点与A组点异侧
					res = false;
					break;
				}
		}
		if (res)  cout << "Yes" << endl;
		else cout << "No" << endl;
	}
	return 0;
}

CCF 202006-2

img

img

#include<iostream>
#include<vector>
#include<map>
using namespace std;

int main()
{
	int n, a, b, index, value;
	long long res = 0;
	map<int, int>m;  //用unordered_map编译错误
	cin >> n >> a >> b;
	while (a--) {
		cin >> index >> value;
		m[index] = value;
	}
	while (b--) {
		cin >> index >> value;
		map<int,int>::iterator it= m.find(index);  //用auto编译错误
		if (it != m.end())
			res += (it->second) * value;
	}
	cout << res << endl;
	return 0;
}

CCF 201912-1

img

#include<iostream>
using namespace std;

bool contains7(int num) {
	bool res = false;
	while (num) {
		if (num % 10 == 7) {
			res = true;
			break;
		}
		num /= 10;
	}
	return res;
}

int main()
{
	int n;
	cin >> n;
	int res[4]{ 0 };
	for (int i = 1, j = 0;; ++i)
	{
		if (i % 7 == 0 || contains7(i)) {
			++res[(i % 4 + 3) % 4];
		}
		else ++j;
		if (j == n)  break;
	}
	for (int i = 0; i < 4; ++i)
		cout << res[i] << endl;
	return 0;
}

CCF 201903-1

试题编号: 201903-1
试题名称: 小中大
时间限制: 1.0s
内存限制: 512.0MB

img

img

分析:

  1. 数据已经有序,所以在存储上可以不必把所有数据存进来(存储空间可优化)

  2. 当序列长度是偶数时,鉴于是两个整数取平均值,所以不需要以下代码:

    #include<iomanip>

    cout<<std::fixed<<std::setprecision(1)

  3. 注意序列长度是奇数时,最后需要将average强制类型转化(否则只有85分)。

#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

int main()
{
	int n;
	cin >> n;
	long long maximum, minimum;
	double average;
	vector<int> arr(n);
	for (int i = 0; i < n; ++i)
		cin >> arr[i];
	if (n % 2 == 1) {
		average = arr[(n-1) / 2];
	}
	else average = (static_cast<double>(arr[n / 2]) + arr[n / 2 - 1]) / 2.0;

	maximum = arr[n - 1];
	minimum = arr[0];

	if (maximum < minimum) swap(maximum, minimum);

	if (average - floor(average) != 0)
		cout << maximum << ' ' << average << ' '<< minimum << endl;
	else cout << maximum << ' ' << static_cast<int>average << ' ' << minimum << endl;
	return 0;
}

CCF 201903-2

试题编号: 201903-2
试题名称: 二十四点
时间限制: 1.0s
内存限制: 512.0MB

img

img

分析:

按照先乘除后加减,从左往右的原则,在处理exp的时候直接计算乘除的结果,若是减法转成加法,最后将add里的数加一下就可以了。

#include<iostream>
#include<vector>
#include<string>
using namespace std;

int main()
{
	int n;
	cin >> n;
	string exp;
	while (n--) {
		vector<int> add;
		cin >> exp;
		for (int i = 0; i < 7; ++i)
			if (isdigit(exp[i]))
				add.push_back(exp[i] - '0');
			else {
				if (exp[i] == '-')  add.push_back(-(exp[++i] - '0'));
				else if (exp[i] == '+') continue;
				else {
					int temp = add.back();
					add.pop_back();
					if (exp[i] == 'x')
						add.push_back(temp * (exp[++i] - '0'));
					else
						add.push_back(temp / (exp[++i] - '0'));
				}
			}
		while (add.size() != 1) {
			add.insert(add.begin(), add[0] + add[1]);
			add.erase(add.begin() + 1, add.begin() + 3);
		}
		if (add[0] == 24)  cout << "Yes" << endl;
		else cout << "No" << endl;
	}
	return 0;
}

CCF 201812-1

试题编号: 201812-1
试题名称: 小明上学
时间限制: 1.0s
内存限制: 512.0MB

题目背景

  小明是汉东省政法大学附属中学的一名学生,他每天都要骑自行车往返于家和学校。为了能尽可能充足地睡眠,他希望能够预计自己上学所需要的时间。他上学需要经过数段道路,相邻两段道路之间设有至多一盏红绿灯。
  京州市的红绿灯是这样工作的:每盏红绿灯有红、黄、绿三盏灯和一个能够显示倒计时的显示牌。假设红绿灯被设定为红灯 r 秒,黄灯 y 秒,绿灯 g 秒,那么从 0 时刻起,[0,r) 秒内亮红灯,车辆不许通过;[r, r+g) 秒内亮绿灯,车辆允许通过;[r+g, r+g+y) 秒内亮黄灯,车辆不许通过,然后依次循环。倒计时的显示牌上显示的数字 l(l > 0)是指距离下一次信号灯变化的秒数。

问题描述

  一次上学的路上,小明记录下了经过每段路的时间,和各个红绿灯在小明到达路口时的颜色和倒计时秒数。希望你帮忙计算此次小明上学所用的时间。

输入格式

  输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 106。
  输入的第二行包含一个正整数 n(n ≤ 100),表示小明总共经过的道路段数和看到的红绿灯数目。
  接下来的 n 行,每行包含空格分隔的两个整数 k、t。k=0 表示经过了一段道路,耗时 t 秒,此处 t 不超过 106;k=1、2、3 时,分别表示看到了一个红灯、黄灯、绿灯,且倒计时显示牌上显示的数字是 t,此处 t 分别不会超过 r、y、g。

输出格式

  输出一个数字,表示此次小明上学所用的时间。

样例输入

30 3 30
8
0 10
1 5
0 11
2 2
0 6
0 3
3 10
0 3

样例输出

70

样例说明

  小明先经过第一段道路,用时 10 秒,然后等待 5 秒的红灯,再经过第二段道路,用时 11 秒,然后等待 2 秒的黄灯和 30 秒的红灯,再经过第三段、第四段道路,分别用时6、3秒,然后通过绿灯,再经过最后一段道路,用时 3 秒。共计 10 + 5 + 11 + 2 + 30 + 6 + 3 + 3=70 秒。

评测用例规模与约定

  测试点 1, 2 中不存在任何信号灯。
  测试点 3, 4 中所有的信号灯在被观察时均为绿灯。
  测试点 5, 6 中所有的信号灯在被观察时均为红灯。
  测试点 7, 8 中所有的信号灯在被观察时均为黄灯。
  测试点 9, 10 中将出现各种可能的情况。

c++版本
#include<bits/stdc++.h>
using namespace std;
int main()
{
	int r,y,g,n,k,t,dist = 0;
	cin>>r>>y>>g>>n;
	while(n--){
		cin>>k>>t;
		if(k == 0 || k == 1)  dist += t;
		else if(k == 2) dist += (t + r); 
	}
	cout<<dist<<endl;
	return 0;
} 

201709 -2

试题编号: 201709-2
试题名称: 公共钥匙盒
时间限制: 1.0s
内存限制: 256.0MB

问题描述

  有一个学校的老师共用N个教室,按照规定,所有的钥匙都必须放在公共钥匙盒里,老师不能带钥匙回家。每次老师上课前,都从公共钥匙盒里找到自己上课的教室的钥匙去开门,上完课后,再将钥匙放回到钥匙盒中。
  钥匙盒一共有N个挂钩,从左到右排成一排,用来挂N个教室的钥匙。一串钥匙没有固定的悬挂位置,但钥匙上有标识,所以老师们不会弄混钥匙。
  每次取钥匙的时候,老师们都会找到自己所需要的钥匙将其取走,而不会移动其他钥匙。每次还钥匙的时候,还钥匙的老师会找到最左边的空的挂钩,将钥匙挂在这个挂钩上。如果有多位老师还钥匙,则他们按钥匙编号从小到大的顺序还。如果同一时刻既有老师还钥匙又有老师取钥匙,则老师们会先将钥匙全还回去再取出。
  今天开始的时候钥匙是按编号从小到大的顺序放在钥匙盒里的。有K位老师要上课,给出每位老师所需要的钥匙、开始上课的时间和上课的时长,假设下课时间就是还钥匙时间,请问最终钥匙盒里面钥匙的顺序是怎样的?

输入格式

  输入的第一行包含两个整数N, K
  接下来K行,每行三个整数w, s, c,分别表示一位老师要使用的钥匙编号、开始上课的时间和上课的时长。可能有多位老师使用同一把钥匙,但是老师使用钥匙的时间不会重叠。
  保证输入数据满足输入格式,你不用检查数据合法性。

输出格式

  输出一行,包含N个整数,相邻整数间用一个空格分隔,依次表示每个挂钩上挂的钥匙编号。

样例输入

5 2
4 3 3
2 2 7

样例输出

1 4 3 2 5

样例说明

  第一位老师从时刻3开始使用4号教室的钥匙,使用3单位时间,所以在时刻6还钥匙。第二位老师从时刻2开始使用钥匙,使用7单位时间,所以在时刻9还钥匙。
  每个关键时刻后的钥匙状态如下(X表示空):
  时刻2后为1X345;
  时刻3后为1X3X5;
  时刻6后为143X5;
  时刻9后为14325。

样例输入

5 7
1 1 14
3 3 12
1 15 12
2 7 20
3 18 12
4 21 19
5 30 9

样例输出

1 2 3 5 4

评测用例规模与约定

  对于30%的评测用例,1 ≤ N, K ≤ 10, 1 ≤ wN, 1 ≤ s, c ≤ 30;
  对于60%的评测用例,1 ≤ N, K ≤ 50,1 ≤ wN,1 ≤ s ≤ 300,1 ≤ c ≤ 50;
  对于所有评测用例,1 ≤ N, K ≤ 1000,1 ≤ wN,1 ≤ s ≤ 10000,1 ≤ c ≤ 100。

cpp

Talk is cheap,show you my code.

#include<bits/stdc++.h>
using namespace std;
struct Key{
	int type;  //使用:-1,归还:+1 
	int time;  //使用时间,归还时间 
	int code;  //钥匙编号
	Key(int x,int y,int z):type(x),time(y),code(z){} 
};
bool cmp(const Key& k1,const Key& k2){
	if(k1.time == k2.time ){
		if(k1.type == 1 && k2.type == 1) return k1.code < k2.code;  //同时还,小编号先还 
		else return  k1.type > k2.type;  //先还再借 
	} 
	return k1.time < k2.time;  //按时间排序
}
int main()
{
	int N,K,w,s,c;
	cin>>N>>K;
	vector<Key> key; 
	vector<int> res(N);
	for(int i = 0; i<N;++i)
		res[i]= i + 1;
	for(int i = 0;i < K;++i){
		cin>>w>>s>>c;
		key.push_back(Key(-1,s,w));
		key.push_back(Key(1,s+c,w));
	}
	sort(key.begin(),key.end(),cmp);
	for(auto k : key){
		if(k.type == -1){
			res[find(res.begin(),res.end(),k.code) - res.begin()] = 0;  //空钥匙位置为0 
		}
		else res[find(res.begin(),res.end(),0) - res.begin()] = k.code;  //从左往右找第一个空位 
	}
	for(int i = 0;i<N;++i){  //控制输出格式
		if(i == N - 1) cout<<res[i]<<endl;
		else cout<<res[i]<<' '; 
    }
    return 0; 
} 

CCF 201912-3

试题编号: 201912-3
试题名称: 化学方程式
时间限制: 1.0s
内存限制: 512.0MB

img

img

image-20201013094539889

#include<iostream>
#include<string>
#include<map>
#include<stack>
#include<vector>
using namespace std;

int getNum(string str, unsigned int& i) {  //获取后置数字并移动指针,从i位置开始检测
	int res = 0;
	if (isdigit(str[i])) {
		res = str[i] - '0';
		while (isdigit(str[++i])) {  //处理两位及以上的数字
			res = res * 10 + (str[i] - '0');
		}
		--i;  //减去最后多自增的一次
	}
	return res;
}

int main()
{
	int n;
	string exp;
	cin >> n;
	while (n--) {
		map<string, int> mLeft, mRight;  //分别存储等号左右两边的化学式的映射
		cin >> exp;
		int base = 1;  //基数
		vector<int> bracket;  //小括号层级
		bool isLeft = true;  //是否在等号左侧
		for (unsigned int i = 0; i < exp.size(); ++i) {  //朴实无华的遍历,处理等式中的每个符号
			if (isdigit(exp[i])) {  //如果是前导数字,因为括号后跟元素后的数字都会被移位处理,所以此处只能是前导数字
					base *= getNum(exp, i);  //基数乘以倍数
			}
			 if (isupper(exp[i])) {  //如果是大写字母
				string elem;
				elem.push_back(exp[i]);
				if (islower(exp[i + 1]))  //是否后边跟一个小写字母
					elem.push_back(exp[++i]);

				if (isdigit(exp[i + 1])) {  //是否后边跟数字
					++i;
					if (isLeft) {  //在等式左
						if (mLeft.find(elem) != mLeft.end())  //是否已有该元素
							mLeft[elem] += base * getNum(exp, i);
						else mLeft[elem] = base * getNum(exp, i);
					}
					else {  //在等式右
						if (mRight.find(elem) != mRight.end())  //是否已有该元素
							mRight[elem] += base * getNum(exp, i);
						else mRight[elem] = base * getNum(exp, i);
					}
				}
				else {  //否则默认是base倍
					if (isLeft) {
						if (mLeft.find(elem) != mLeft.end())
							mLeft[elem] += base;
						else mLeft[elem] = base;
					}
					else {
						if (mRight.find(elem) != mRight.end())
							mRight[elem] += base;
						else mRight[elem] = base;
					}
				}
			}
			else if (exp[i] == '+') {  //处理加号
				base = 1;
			}
			else if (exp[i] == '(') {  //处理左括号
				stack<int> stk;
				stk.push(1);
				unsigned int j = i;  //不移动遍历的指针
				while (!stk.empty()) {  //栈处理
					if (exp[j + 1] == '(')
						stk.push(1);  //push('(')跟push(1)是效果一样
					else if (exp[j + 1] == ')')
						stk.pop();
					++j;
				}
				if (isdigit(exp[++j])) {  //获取括号后的数值
					bracket.push_back(getNum(exp, j));  //bracket中下标越小,括号层次越外
					base *= bracket.back();  //改变基数
				}
				else {
					bracket.push_back(1);
				}
			}
			else if (exp[i] == ')') {  //处理右括号
				base /= bracket.back();
				bracket.pop_back();
				while (isdigit(exp[i + 1])) ++i;  //若是右括号后跟数字,移动忽略,否则误认为前导数字
			}
			else if (exp[i] == '=') {  //处理等号
				isLeft = false;
				base = 1;
			}
		}
		bool res = true;
		map<string, int>::iterator left = mLeft.begin(), right = mRight.begin();
		while (left != mLeft.end() && right != mRight.end()) {  //因为map有序,所以可以检查化学式是否一致,对应化学式个数是否一致
			if (left->first != right->first || left->second != right->second) {
				res = false;
				break;
			}
			++left, ++right;
		}
		if(left != mLeft.end() || right != mRight.end())  res = false;  //检查总化学式个数是否一致
		if (res) cout << "Y" << endl;
		else cout << 'N' << endl;
	}
	return 0;
}
posted @ 2020-10-09 16:07  kite97  阅读(741)  评论(0编辑  收藏  举报