CCF CSP认证历年真题(更新中)

首页 - 计算机软件能力认证考试系统


2023-09

试题编号:202309-1

坐标变换(其一)

问题描述

对于平面直角坐标系上的坐标 (x,y),小 P 定义了一个包含 n 个操作的序列 T=(t1,t2,⋯,tn)。其中每个操作 ti(1≤i≤n)包含两个参数 dxi 和 dyi,表示将坐标 (x,y) 平移至 (x+dxi,y+dyi) 处。

现给定 m 个初始坐标,试计算对每个坐标 (xj,yj)(1≤j≤m)依次进行 T 中 n 个操作后的最终坐标。

输入格式

从标准输入读入数据。

输入共 n+m+1 行。

输入的第一行包含空格分隔的两个正整数 n 和 m,分别表示操作和初始坐标个数。

接下来 n 行依次输入 n 个操作,其中第 i(1≤i≤n)行包含空格分隔的两个整数 dxi、dyi。

接下来 m 行依次输入 m 个坐标,其中第 j(1≤j≤m)行包含空格分隔的两个整数 xj、yj。

输出格式

输出到标准输出中。

输出共 m 行,其中第 j(1≤j≤m)行包含空格分隔的两个整数,表示初始坐标 (xj,yj) 经过 n 个操作后的位置。

样例输入

3 2
10 10
0 0
10 -20
1 -1
0 0

样例输出

21 -11
20 -10

样例说明

第一个坐标 (1,−1) 经过三次操作后变为 (21,−11);第二个坐标 (0,0) 经过三次操作后变为 (20,−10)。

评测用例规模与约定

全部的测试数据满足:n,m≤100,所有输入数据(x,y,dx,dy)均为整数且绝对值不超过 100000。

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP (C++语言)

解题思路:

// C++
#include<iostream>
using namespace std;

int main(){
	int n, m;
	cin>>n>>m;
	int a = 0, b = 0;
	while(n--){
		int dx, dy;
		cin>>dx>>dy;
		a += dx;
		b += dy;
	}
	int x, y;
	while(m--){
		cin>>x>>y;
		cout<<x + a<<" "<<y + b<<endl; 
	}
	return 0;
} 

试题编号:202309-02

坐标变换(其二)

问题描述

对于平面直角坐标系上的坐标 (x,y),小 P 定义了如下两种操作:

  1. 拉伸 k 倍:横坐标 x 变为 kx,纵坐标 y 变为 ky;

  2. 旋转 θ:将坐标 (x,y) 绕坐标原点 (0,0) 逆时针旋转 θ 弧度(0≤θ<2π)。易知旋转后的横坐标为 xcos⁡θ−ysin⁡θ,纵坐标为 xsin⁡θ+ycos⁡θ。

设定好了包含 n 个操作的序列 (t1,t2,⋯,tn) 后,小 P 又定义了如下查询:

  • i j x y:坐标 (x,y) 经过操作 ti,⋯,tj(1≤i≤j≤n)后的新坐标。

对于给定的操作序列,试计算 m 个查询的结果。

输入格式

从标准输入读入数据。

输入共 n+m+1 行。

输入的第一行包含空格分隔的两个正整数 n 和 m,分别表示操作和查询个数。

接下来 n 行依次输入 n 个操作,每行包含空格分隔的一个整数(操作类型)和一个实数(k 或 θ),形如 1 k(表示拉伸 k 倍)或 2 θ(表示旋转 θ)。

接下来 m 行依次输入 m 个查询,每行包含空格分隔的四个整数 i、j、x 和 y,含义如前文所述。

输出格式

输出到标准输出中。

输出共 m 行,每行包含空格分隔的两个实数,表示对应查询的结果。

样例输入

10 5
2 0.59
2 4.956
1 0.997
1 1.364
1 1.242
1 0.82
2 2.824
1 0.716
2 0.178
2 4.094
1 6 -953188 -946637
1 9 969538 848081
4 7 -114758 522223
1 9 -535079 601597
8 8 159430 -511187

样例输出

-1858706.758 -83259.993
-1261428.46 201113.678
-75099.123 -738950.159
-119179.897 -789457.532
114151.88 -366009.892

样例说明

第五个查询仅对输入坐标使用了操作八:拉伸 0.716 倍。

横坐标:159430×0.716=114151.88

纵坐标:−511187×0.716=−366009.892

由于具体计算方式不同,程序输出结果可能与真实值有微小差异,样例输出仅保留了三位小数。

评测用例规模与约定

80% 的测试数据满足:n,m≤1000;

全部的测试数据满足:

  • n,m≤100000;

  • 输入的坐标均为整数且绝对值不超过 1000000;

  • 单个拉伸操作的系数 k∈[0.5,2];

  • 任意操作区间 ti,⋯,tj(1≤i≤j≤n)内拉伸系数 k 的乘积在 [0.001,1000] 范围内

评分方式

如果你输出的浮点数与参考结果相比,满足绝对误差不大于 0.1,则该测试点满分,否则不得分。

提示

  • C/C++:建议使用 double 类型存储浮点数,并使用 scanf("%lf", &x); 进行输入,printf("%f", x); 输出,也可以使用 cin 和 cout 输入输出浮点数;#include <math.h> 后可使用三角函数 cos() 和 sin()

  • Python:直接使用 print(x) 即可输出浮点数 xfrom math import cos, sin 后可使用相应三角函数。

  • Java:建议使用 double 类型存储浮点数,可以使用 System.out.print(x); 进行输出;可使用 Math.cos() 和 Math.sin() 调用三角函数。

时间限制:2.0s

内存限制:512.0MB

编译环境:DEV-CPP (C++语言)

// 暴力法(80分)
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;

typedef pair<int, double> PII;

int main(){
	int n, m;
	cin>>n>>m;
	vector<PII> v;
	for(int i = 0; i < n; i++){
		int op;
		double x;
		cin>>op>>x;
		v.push_back(make_pair(op, x));
	}
	
	while(m--){
		int i, j;
		double x, y;
		cin>>i>>j>>x>>y;
		for(int k = i - 1; k <= j - 1; k++){
			if(v[k].first == 1){
				x *= v[k].second;
				y *= v[k].second;
			}else{
				double tx, ty;
				tx = x * cos(v[k].second) - y * sin(v[k].second);
				ty = x * sin(v[k].second) + y * cos(v[k].second);
				x = tx;
				y = ty; 
			}
		}
		printf("%.3llf %.3llf", x, y);
		if(m)    cout<<endl;
	}
	return 0;
}

解题思路:对于每个给出的坐标,题目需要我们求经过i~j步操作变换后得到的结果。只考虑存在拉伸操作的情况下,最终拉伸系数等于每次拉伸操作系数的乘积。只考虑存在旋转操作的情况下,最终旋转的角度等于每次旋转操作角度的和。因为拉伸操作和旋转操作是互不影响的,因此可以使用两个数组分别存储拉伸操作的前缀积以及旋转操作的前缀和。对于每个坐标给出的i~j步操作,利用拉伸操作的前缀积数组以及旋转操作的前缀和数组快速求出拉伸系数和旋转角度即可。

// 满分解 前缀和的思想
#include<stdio.h>
#include<math.h>
using namespace std;

int main(){
	int n, m;
	scanf("%d %d", &n, &m);
	double stretchPrefix[n + 1] = {1}, rotatePrefix[n + 1] = {0};  // 拉伸操作的前缀积,旋转操作的前缀和
	for(int i = 0; i < n; ++i){
		int type;
		double val;
		scanf("%d %lf", &type, &val);
		switch(type){
			case 1:
				stretchPrefix[i + 1] = val * stretchPrefix[i];
				rotatePrefix[i + 1] = rotatePrefix[i];
				break;
			case 2:
				stretchPrefix[i + 1] = stretchPrefix[i];
				rotatePrefix[i + 1] = val + rotatePrefix[i];
				break;
			default:
				break;
		}
	} 
	for(int mi = 0; mi < m; ++mi){
		int i, j;
		double x, y;
		scanf("%d %d %lf %lf", &i, &j, &x, &y);
		double k = stretchPrefix[j] / stretchPrefix[i - 1];  // 求经过了i - j步的操作后的拉伸系数
		double theta = rotatePrefix[j] - rotatePrefix[i - 1];  // 求经过了i - j步的操作后的旋转角度
		double x1 = k * x;
		double y1 = k * y;
		double x2 = x1 * cos(theta) - y1 * sin(theta);
		double y2 = x1 * sin(theta) + y1 * cos(theta);
		printf("%lf %lf\n", x2, y2);  
	}
	return 0;
}

试题编号:202309-3

梯度求解

背景

西西艾弗岛运营公司近期在大力推广智能化市政管理系统。这套系统是由西西艾弗岛信息中心研发的。它的主要目的是,通过详细评估岛上各处的市政设施的状况,来指导市政设施的维护和更新。这套系统的核心是一套智能化的传感器网络,它能够自动地对岛上的市政设施进行评估。对市政设施的维护是需要一定成本的,而年久失修的市政设施也可能给岛上的居民造成损失。为了能够平衡成本和收益,信息中心研发了一款数学模型,描述这些变量和损益之间的复杂数学关系。要想得到最优化的成本,就要依靠梯度下降算法来求解。

梯度下降算法中,求解函数在一点处对某一自变量的偏导数是十分重要的。小 C 负责实现这个功能,但是具体的技术实现,他还是一头雾水,希望你来帮助他完成这个任务。

问题描述

设被求算的函数 u=f(x1,x2,…,xn),本题目要求你求出 u 对 xi 在 (a1,a2,…,an) 处的偏导数 ∂u/∂xi(a1,a2,…,an)。

求算多元函数在一点处对某一自变量的偏导数的方法是:将函数的该自变量视为单一自变量,其余自变量认为是常数,运用一元函数求导的方法求出该偏导数表达式,再代入被求算的点的坐标即可。

例如,要求算 u=x1⋅x1⋅x2 对 x1 在 (1,2) 处的偏导数,可以将 x2 视为常数,依次应用求导公式。先应用乘法的求导公式:(x1⋅(x1⋅x2))′=x1′(x1⋅x2)+x1(x1⋅x2)′;再应用常数与变量相乘的求导公式,得到 x1′⋅x1⋅x2+x1⋅x2⋅x1′;最后应用公式 x′=1 得到 1⋅x1⋅x2+x1⋅x2⋅1。整理得 ∂u/∂x1=2x2⋅x1。再代入 (1,2) 得到 ∂u/∂x1(1,2)=4。

常见的求导公式有:

  • (是常数)c′=0 (c是常数)
  • x′=1
  • (u+v)′=u′+v′
  • (是常数)(cu)′=cu′ (c是常数)
  • (u−v)′=u′−v′
  • (uv)′=u′v+uv′

本题目中,你需要求解的函数 f 仅由常数、自变量和它们的加法、减法、乘法组成。且为程序识读方便,函数表达式已经被整理为逆波兰式(后缀表达式)的形式。例如,x1⋅x1⋅x2 的逆波兰式为 x1 x1 * x2 *。逆波兰式即为表达式树的后序遍历的结果。若要从逆波兰式还原原始计算算式,可以按照这一方法进行:假设存在一个空栈 S,依次读取逆波兰式的每一个元素,若读取到的是变量或常量,则将其压入 S 中;若读取到的是计算符号,则从 S 中取出两个元素,进行相应运算,再将结果压入 S 中。最后,若 S 中存在唯一的元素,则该表达式合法,其值即为该元素的值。例如对于逆波兰式 x1 x1 * x2 *,按上述方法读取,栈 S 的变化情况依次为(左侧是栈底,右侧是栈顶):

  1. x1;
  2. x1,x1;
  3. (x1⋅x1);
  4. (x1⋅x1),x2;
  5. ((x1⋅x1)⋅x2)。

输入格式

从标准输入读入数据。

输入的第一行是由空格分隔的两个正整数 n、m,分别表示要求解函数中所含自变量的个数和要求解的偏导数的个数。

输入的第二行是一个逆波兰式,表示要求解的函数 f。其中,每个元素用一个空格分隔,每个元素可能是:

  • 一个自变量 xi,用字符 x 后接一个正整数表示,表示第 i 个自变量,其中 i=1,2,…,n。例如,x1 表示第一个自变量 x1。
  • 一个整常数,用十进制整数表示,其值在 −10^5 到 10^5 之间。
  • 一个运算符,用 + 表示加法,- 表示减法,* 表示乘法。

输入的第三行到第 m+2 行,每行有 n+1 个用空格分隔的整数。其中第一个整数是要求偏导数的自变量的编号 i=1,2,…,n,随后的整数是要求算的点的坐标 a1,a2,…,an。
输入数据保证,对于所有的 i=1,2,…,n,ai 都在 −10^5 到 10^5 之间。

输出格式

输出到标准输出中。

输出 m 行,每行一个整数,表示对应的偏导数对 10^9+7 取模的结果。即若结果为 y,输出为 k,则保证存在整数 t,满足 y=k+t⋅(10^9+7) 且 0≤k<10^9+7。

样例1输入

2 2
x1 x1 x1 * x2 + *
1 2 3
2 3 4

样例1输出

15
3

样例1说明

样例2输入

3 5
x2 x2 * x2 * 0 + -100000 -100000 * x2 * -
3 100000 100000 100000
2 0 0 0
2 0 -1 0
2 0 1 0
2 0 100000 0

样例2输出

0
70
73
73
999999867

样例2说明

评测用例规模与约定

测试点nm表达式的性质
1, 2=1≤100仅含有 1 个元素
3, 4=1≤100仅含有一个运算符
5, 6≤10≤100含有不超过 120 个元素,且不含乘法
7, 8≤10≤100含有不超过 120 个元素
9, 10≤100≤100含有不超过 120 个元素

提示

C++ 中可以使用 std::getline(std::cin, str) 读入字符串直到行尾。

当计算整数 n 对 M 的模时,若 n 为负数,需要注意将结果调整至区间 [0,M) 内。

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include <bits/stdc++.h>
using namespace std;
 
const int mo = 1e9+7;
#define CONST -1
#define VAR -2
#define OP -3
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    string s;
    int n, m;
    cin >> n >> m;
    getline(cin, s); // '\n'
    getline(cin, s);
    istringstream qwq(s);
    vector<int> l;
    vector<int> r;
    vector<int> info;
    vector<int> kind;
    stack<int> id;
    int node_id = 0;
    while(getline(qwq, s, ' ')){
        if (s.size() == 1 && (s[0] == '+' || s[0] == '*' || s[0] == '-')){
            int rson = id.top();
            id.pop();
            int lson = id.top();
            id.pop();
            l.push_back(lson);
            r.push_back(rson);
            info.push_back(s[0]);
            kind.push_back(OP);
 
            id.push(node_id);
            ++ node_id;
        }else if (s[0] == 'x'){
            int x = stoi(s.substr(1));
            -- x;
            l.push_back(-1);
            r.push_back(-1);
            info.push_back(x);
            kind.push_back(VAR);
 
            id.push(node_id);
            ++ node_id;
        }else{
            int x = stoi(s);
            l.push_back(-1);
            r.push_back(-1);
            info.push_back(x);
            kind.push_back(CONST);
 
            id.push(node_id);
            ++ node_id;
        }
    }
    int root = id.top();
    vector<int> a(n);
 
    function<array<int, 2>(int, int)> solve = [&](int u, int x){
        if (kind[u] == VAR){
            return array<int, 2>{a[info[u]], (info[u] == x)};
        }else if (kind[u] == CONST){
            return array<int, 2>{info[u], 0};
        }else{
            auto lans = solve(l[u], x), rans = solve(r[u], x);
            int sum = 0, dsum = 0;
            if (info[u] == '+'){
                sum = lans[0] + rans[0];
                dsum = lans[1] + rans[1];
                if (sum >= mo)  sum -= mo;
                if (dsum >= mo) dsum -= mo;
            }else if (info[u] == '-'){
                sum = lans[0] - rans[0];
                dsum = lans[1] - rans[1];
                if (sum >= mo)  sum -= mo;
                if (dsum >= mo) dsum -= mo;
            }else{
                sum = 1ll * lans[0] * rans[0] % mo;
                dsum = (1ll * lans[0] * rans[1] % mo + 1ll * lans[1] * rans[0] % mo);
                if (dsum >= mo) dsum -= mo;
            }
            if (sum < 0)
                sum += mo;
            if (dsum < 0)
                dsum += mo;
            return array<int, 2>{sum, dsum};
        }
    };
    for(int i = 0; i < m; ++ i){
        int x;
        cin >> x;
        -- x;
        for(auto &i : a)
            cin >> i;
        cout << solve(root, x)[1] << '\n';
    }
    return 0;
}

试题编号:202309-4

阴阳龙

问题描述

输入格式

从标准输入读入数据。

第一行四个正整数 n,m,p,q;

接下来 p 行,第 i 行两个正整数 (xi,yi) 表示第 i 名员工的初始位置。

保证所有员工初始所在的位置两两不同

接下来 q 行,第 i 行三个正整数 ui,vi,ti 表示西西艾弗遗迹探索有限公司探测到的第 i 次阴阳龙现身的位置和强度。

输出格式

样例输入

3 3 9 1
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
2 2 1

样例输出

20

样例说明

阴阳龙现身前,每个员工所在的位置如下:

阴阳龙现身一次后,每个员工所在位置如下:

评测用例规模与约定

子任务编号n≤m≤p≤q≤子任务分值
11000100010510540
21091091000100015
310510510510525
410910910510520

对于全部数据:

1≤n,m≤10^9,1≤p,q≤1×10^5,1≤xi,u≤n,1≤yi,v≤m,1≤ti≤7。

保证所有员工初始所在的位置两两不同

时间限制:2.0s

内存限制:1.0GB

编译环境:DEV-CPP(C++语言)

试题编号:202309-05

狙击

问题描述

上回提到,西西艾弗岛下方有一个庞大的遗迹群,栖息着一种名为“阴阳龙”的神兽。然而隔壁的狄迪吉岛盯上了西西艾弗岛,决定发动一场战争,试图从遗迹群中掠夺有价值的宝物。由此,西西艾弗岛不得不陷入一场漫长的阻击战中,史称“阴阳龙阻击战”。

狄迪吉岛拥有胜过西西艾弗岛的科技实力和武装水平,西西艾弗岛很快发现形势不妙:全歼敌军似乎是不可能的,唯一的策略是凭借主场作战的优势和人海战术,尽可能给敌军带来损失,当敌军发现发动进攻的损失明显超过收益时,就会无趣而归。

具体而言,西西艾弗岛共有 n 座城市,有 n−1 条道路连接这些城市,使得所有城市之间均可以通过道路互相到达。容易发现,任意两座城市之间都有唯一一条不经过重复城市的路径。

由于缺乏城市巷战的实力,西西艾弗岛决定将防御重心放在道路上。在每条道路上均派遣了一定的军队防守,当敌军经过时对其发动阻击。虽然由于实力的差距,并不能阻止敌军通过道路,但仍然可以对敌军造成一定的损失。

然而,敌军具有更强的科技,可以趁机对道路附近的遗迹进行探索,并掠夺其中的宝物——这也正是敌军发动战争的意义所在。如此,敌军通过一条道路时,“发掘宝物的收益”w 和“受到阻击的损失”b 两个值是独立的。

西西艾弗岛事先在狄迪吉岛中安插了一系列间谍,得到的情报消息如下:敌军将选择西西艾弗岛的两座城市作为进攻的“起点”和“终点”,并派遣军队在进攻起点城市登陆,沿两座城市间唯一的路径进攻至终点城市。同时,间谍还背负着另外一个重要的使命:影响敌军对于起点和终点城市的决策,使得敌军受到的总损失尽可能大,其中“总损失”定义为敌军经过的每条道路上的“受到阻击的损失”减去“发掘宝物的收益”之和,即 总损失是路径上的每条边总损失=∑e是路径上的每条边(be−we)。

此外,遗迹中宝物的价值与所处的环境属性密切相关,而阴阳龙的“现身”会使得环境的阴阳属性发生变化,这会使得敌军通过现身位置处的某一条道路时“发掘宝物的收益”w 发生变化。

这样的“阴阳龙现身”事件共会发生 m 次,你的任务就是帮助间谍计算出在所有事件前及每次事件后,敌军对于起点和终点城市的决策应当怎样改变,以最大化敌军的总损失。

输入格式

输出格式

输出到标准输出中。

输出 m+1 行,每行一个非负整数,分别表示在所有事件前及每次事件后,对敌军造成的最大总损失。

样例输入

5 3
1 2 6 4
2 3 2 1
3 4 5 3
3 5 8 5
3 2
4 3
1 1

样例输出

0
1
3
4

样例说明

在最初,由于敌人攻打每一条道路都会有正收益,因此间谍最好的策略就是将进攻起点和终点选为同一座城市,这样敌军的总损失为 0。

第 1 次事件后,间谍可以将进攻起点和终点分别选在城市 3 和 4,这样敌军的总损失为 3−2=1。

第 2 次事件后,间谍可以将进攻起点和终点分别选在城市 4 和 5,这样敌军的总损失为 (3−2)+(5−3)=3。

第 3 次事件后,间谍可以将进攻起点和终点分别选在城市 1 和 5,这样敌军的总损失为 (4−1)+(1−2)+(5−3)=4。

评测用例规模与约定

对于所有测试数据保证:2≤n≤10^5,0≤m≤10^5,1≤ui,vi≤n,1≤xi≤n−1,0≤wi,bi,yi≤10^9。

测试点编号n≤m≤特殊性质
12020
2300300
3∼430003000A
5∼630003000B
7∼930003000
1010^50A
1110^50B
1210^50
13∼1510^510^5A
16∼1810^510^5B
19∼2110^510^5C
22∼2510^510^5

特殊性质 A:ui=i,vi=i+1。

特殊性质 B:0≤wi,yi≤10^8≤bi。

特殊性质 C:保证任意两座城市均可在经过不超过 100 条道路的前提下互相到达。

时间限制:2.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言)

2023-05

试题编号:202305-1

重复局面

题目背景

国际象棋在对局时,同一局面连续或间断出现3次或3次以上,可由任意一方提出和棋。

问题描述

国际象棋每一个局面可以用大小为 8×8 的字符数组来表示,其中每一位对应棋盘上的一个格子。六种棋子王、后、车、象、马、兵分别用字母 kqrbnp 表示,其中大写字母对应白方、小写字母对应黑方。棋盘上无棋子处用字符 * 表示。两个字符数组的每一位均相同则说明对应同一局面。

现已按上述方式整理好了每步棋后的局面,试统计每个局面分别是第几次出现。

输入格式

从标准输入读入数据。

输入的第一行包含一个正整数 n,表示这盘棋总共有 n 步。

接下来 8×n 行,依次输入第 1 到第 n 步棋后的局面。具体来说每行包含一个长度为 8 的字符串,每 8 行字符串共 64 个字符对应一个局面。

输出格式

输出到标准输出中。

输出共 n 行,每行一个整数,表示该局面是第几次出现。

样例输入

8
********
******pk
*****r*p
p*pQ****
********
**b*B*PP
****qP**
**R***K*
********
******pk
*****r*p
p*pQ****
*b******
****B*PP
****qP**
**R***K*
********
******pk
*****r*p
p*p*****
*b**Q***
****B*PP
****qP**
**R***K*
******k*
******p*
*****r*p
p*p*****
*b**Q***
****B*PP
****qP**
**R***K*
******k*
******p*
*****r*p
p*pQ****
*b******
****B*PP
****qP**
**R***K*
********
******pk
*****r*p
p*pQ****
*b******
****B*PP
****qP**
**R***K*
********
******pk
*****r*p
p*p*****
*b**Q***
****B*PP
****qP**
**R***K*
********
******pk
******rp
p*p*****
*b**Q***
****B*PP
****qP**
**R***K*

样例输出

1
1
1
1
1
2
2
1

样例说明

第 6、7 步后的局面分别与第 2、3 步后的局面相同。第 8 步后的局面与上图相对应。

子任务

输入数据满足 n≤100。

提示

判断重复局面仅涉及字符串比较,无需考虑国际象棋实际行棋规则。

解题思路:把输入的每个棋盘的棋子保存到字符数组中,然后判断这个字符串在map(会自动排序)中是否出现过,若出现过,则出现次数加一,否则记录这个字符串的出现次数为1就行。

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<bits/stdc++.h>
using namespace std;
int n;
char pieces[64];
map<string, int> status_map;
int main(){
	cin>>n;
	for(int i = 0; i < n; i++){
		for(int j =0; j < 64; j++)
			cin>>pieces[j];
		if(status_map.count(pieces))
			status_map[pieces]++;
		else
			status_map[pieces] = 1;
		cout<<status_map[pieces]<<endl;
	}
	return  0;
} 

试题编号:202305-02

矩阵运算

题目背景

Softmax(Q×K\tfrac{T}{})×V 是 Transformer 中注意力模块的核心算式,其中 Q、K 和 V 均是 n 行 d 列的矩阵,K\tfrac{T}{} 表示矩阵 K 的转置,× 表示矩阵乘法。

问题描述

为了方便计算,顿顿同学将 Softmax 简化为了点乘一个大小为 n 的一维向量 W:
(W⋅(Q×K\tfrac{T}{}))×V
点乘即对应位相乘,记 W(i) 为向量 W 的第 i 个元素,即将 (Q×K\tfrac{T}{}) 第 i 行中的每个元素都与 W(i) 相乘。

现给出矩阵 Q、K 和 V 和向量 W,试计算顿顿按简化的算式计算的结果。

输入格式

从标准输入读入数据。

输入的第一行包含空格分隔的两个正整数 n 和 d,表示矩阵的大小。

接下来依次输入矩阵 Q、K 和 V。每个矩阵输入 n 行,每行包含空格分隔的 d 个整数,其中第 i 行的第 j 个数对应矩阵的第 i 行、第 j 列。

最后一行输入 n 个整数,表示向量 W。

输出格式

输出到标准输出中。

输出共 n 行,每行包含空格分隔的 d 个整数,表示计算的结果。

样例输入

3 2
1 2
3 4
5 6
10 10
-20 -20
30 30
6 5
4 3
2 1
4 0 -5

样例输出

480 240
0 0
-2200 -1100

子任务

70% 的测试数据满足:n≤100 且 d≤10;输入矩阵、向量中的元素均为整数,且绝对值均不超过 30。

全部的测试数据满足:n≤104 且 d≤20;输入矩阵、向量中的元素均为整数,且绝对值均不超过 1000。

提示

请谨慎评估矩阵乘法运算后的数值范围,并使用适当数据类型存储矩阵中的整数。

时间限制:5.0s

内存限制:512.0MB

编程语言:Dev-CPP(C++语言C++11标准)

解题思路:重点在于时间复杂度,如果先计算QK矩阵相乘,会得到n*n的矩阵,会显示超时,所以要先计算后面两个矩阵,即K\tfrac{T}{} * V。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 10010, D = 30;
LL tmp[D][D], ans[N][N];
int n, d;
int Q[N][D], K[N][D], V[N][D], W[N];

int main(){
	cin>>n>>d;
	for(int i = 1; i <= n; i++)
		for(int j = 1; i <= d; j++)
			cin>>Q[i][j];
	
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= d; j++)
			cin>>K[i][j];
	
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= d; j++)
			cin>>V[i][j];
	
	for(int i = 1; i <= n; i++)
		cin>>W[i];
	
	// tmp = 计算K的转置 * V
	for(int i = 1; i <= d; i++)
		for(int j = 1; j <= d; j++)
			for(int k = 1; k <= n; k++)
				tmp[i][j] += K[k][j] * V[k][j];
	
	// ans = 计算Q * tmp * W
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= d; j++)
		{
			for(int k = 1; k <= d; k++)
				ans[i][j] += Q[i][k] * tmp[k][j];
			ans[i][j] *= (LL) W[i];
		 } 
		 
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= d; j++)
			cout<<ans[i][j]<<" ";
		cout<<endl;
	}
	return 0;
}

2023-03

试题编号:202303-1

田地丈量

问题描述

西西艾弗岛上散落着 n 块田地。每块田地可视为平面直角坐标系下的一块矩形区域,由左下角坐标 (x1,y1) 和右上角坐标 (x2,y2) 唯一确定,且满足 x1<x2、y1<y2。这 n 块田地中,任意两块的交集面积均为 0,仅边界处可能有所重叠。

最近,顿顿想要在南山脚下开垦出一块面积为 a×b 矩形田地,其左下角坐标为 (0,0)、右上角坐标为 (a,b)。试计算顿顿选定区域内已经存在的田地面积。

输入格式

从标准输入读入数据。

输入共 n+1 行。

输入的第一行包含空格分隔的三个正整数 n、a 和 b,分别表示西西艾弗岛上田地块数和顿顿选定区域的右上角坐标。

接下来 n 行,每行包含空格分隔的四个整数 x1、y1、x2 和 y2,表示一块田地的位置。

输出格式

输出到标准输出。

输出一个整数,表示顿顿选定区域内的田地面积。

样例输入

4 10 10
0 0 5 5
5 -2 15 3
8 8 15 15
-2 10 3 15

样例输出

44

样例解释

如图所示,选定区域内田地(绿色区域)面积为 44。

子任务

全部的测试数据满足 n≤100,且所有输入坐标的绝对值均不超过 104。

时间限制:1.0s

内存限制:512.0MB

编译环境:DEV-CPP(C++语言C++11标准)

解题思路:求所圈的矩形和其他已有矩形的交集面积,交集面积的右边界即两个相交矩形的最右边的边界,即min(a, points[i][2]),左边界即两个矩形的最右边的边界,即max(0, points[i][0]).上下边也是一样的道理。通过判断x和y是否大于零,可以判断出矩阵是否交叉,若存在则sum += x * y;

#include<iostream>
using namespace std;

int main(){
	int n, a, b;
	cin>>n>>a>>b;
	int x1, y1, x2, y2;
	int x, y;
	int sum = 0;
	for(int i = 1; i <= n; i++){
		cin>>x1>>y1>>x2>>y2;
		x = min(a, x2) - max(0, x1);  // 右边界 - 左边界 
		y = min(b, y2) - max(0, y1);  // 上边界 - 下边界 
		if(x >= 0 && y >= 0)
			sum += x * y;
	}
	cout<<sum;
	return 0;
}

试题编号:202303-2

垦田计划

问题描述

顿顿总共选中了 n 块区域准备开垦田地,由于各块区域大小不一,开垦所需时间也不尽相同。据估算,其中第 i 块(1≤i≤n)区域的开垦耗时为 ti 天。这 n 块区域可以同时开垦,所以总耗时 tTotal 取决于耗时最长的区域,即:tTotal=max{t1,t2,⋯,tn}

为了加快开垦进度,顿顿准备在部分区域投入额外资源来缩短开垦时间。具体来说:

  • 在第 i 块区域投入 ci 单位资源,便可将其开垦耗时缩短 1 天;

  • 耗时缩短天数以整数记,即第 i 块区域投入资源数量必须是 ci 的整数倍;

  • 在第 i 块区域最多可投入 ci×(ti−k) 单位资源,将其开垦耗时缩短为 k 天;

  • 这里的 k 表示开垦一块区域的最少天数,满足 0<k≤min{t1,t2,⋯,tn};换言之,如果无限制地投入资源,所有区域都可以用 k 天完成开垦。

现在顿顿手中共有 m 单位资源可供使用,试计算开垦 n 块区域最少需要多少天?

输入格式

从标准输入读入数据。

输入共 n+1 行。

输入的第一行包含空格分隔的三个正整数 n、m 和 k,分别表示待开垦的区域总数、顿顿手上的资源数量和每块区域的最少开垦天数。

接下来 n 行,每行包含空格分隔的两个正整数 ti 和 ci,分别表示第 i 块区域开垦耗时和将耗时缩短 1 天所需资源数量。

输出格式

输出到标准输出。

输出一个整数,表示开垦 n 块区域的最少耗时。

样例输入1

4 9 2
6 1
5 1
6 2
7 1

样例输出1

5

样例解释

如下表所示,投入 5 单位资源即可将总耗时缩短至 5 天。此时顿顿手中还剩余 4 单位资源,但无论如何安排,也无法使总耗时进一步缩短。

i基础耗时 ti缩减 1 天所需资源 ci投入资源数量实际耗时
16115
25105
36225
47125

样例输入2

4 30 2
6 1
5 1
6 2
7 1

样例输出2

2

样例解释

投入 20 单位资源,恰好可将所有区域开垦耗时均缩短为 k=2 天;受限于 k,剩余的 10 单位资源无法使耗时进一步缩短。

子任务

70% 的测试数据满足:0<n,ti,ci≤100 且 0<m≤106;

全部的测试数据满足:0<n,ti,ci≤105 且 0<m≤109。

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:总耗时取决于耗时最长的区域,因此,我们只需要用资源把最大耗时降到最小,就等同于将最终的开垦天使降到最小。

#include<bits/stdc++.h>
#include<iostream> 
using namespace std;

int n, k;
long long int m;
map<int, int>tim, cost, flag;
// 第i块区域开垦耗时、将耗时缩短1天所需的资源数量、 
int main(){
	cin >> n >> m >> k;  // 待开垦的区域总数、资源数量、每块区域的最少开垦天数
	int max = 0;
	for(int i = 0; i < n; ++i){
		cin >> tim[i] >> cost[i];
		max = max > tim[i] ? max : tim[i];  // 找到开垦一块区域的最长耗时 
		flag[tim[i]] += cost[i];
		// flag[i] 为所有用时i天的区域缩短一天所用资源数量 
	} 
	for(int i = max; i > k; i--){
		if(m >= flag[i]){
			m = m - flag[i];
			flag[i - 1] += flag[i];  //对于已经被缩短的天数,将其所要的资源加到前一天上
			max--;
		}else
			break;
	} 
	cout<<max;
	return 0;
}

试题编号:202303-3

LDAP

题目背景

西西艾弗岛运营公司是一家负责维护和运营岛上基础设施的大型企业,拥有数千名员工。公司内有很多 IT 系统。为了能够实现这些 IT 系统的统一认证登录,公司 IT 部门决定引入一套 LDAP 系统来管理公司内的用户信息。轻型目录访问协议(Lightweight Directory Access Protocol,LDAP)是一种用于访问和维护目录服务的应用层协议,基于它的数据库可以用树形结构来组织和存储数据。每一笔数据,都包含了一个唯一的标识符(DN,Distinguished Name),以及一系列的属性(Attribute)。

不同的 IT 系统,允许访问的用户是不相同的。每个信息系统都有一个表达式,用来描述允许访问的用户。
这个表达式可以按照某一个属性的值作为条件来匹配用户,也可以用多个条件的逻辑组合来匹配用户。
小 C 被安排来实现这样一个算法,给定一个 IT 系统的匹配表达式,找到所有与之匹配的用户的 DN。

问题描述

为了简化该问题,我们约定,每个用户的 DN 是一个正整数,且不会重复。有若干种用户的属性,用正整数编号。每个用户可以具有这些属性中的若干个,且每个属性只能有一个值。每个属性的值也是一个正整数。例如,假定有两个用户:用户 1 和用户 2,他们的 DN 分别是 1 和 2。一共有 3 种属性。用户 1 具有属性 1 和属性 2,且属性 1 的值为 2,属性 2 的值为 3;但不具有属性 3。用户 2 具有属性 2 和属性 3,且属性 2 的值为 3,属性 3 的值为 1;但不具有属性 1。如下表所示:

DN属性 1属性 2属性 3
123N/A
2N/A31

一个匹配表达式可以是一个属性的值,也可以是多个匹配表达式的逻辑组合。只匹配一个属性的值的表达式称为原子表达式,原子表达式的形式为 <属性编号><操作符><属性值>。其中操作符有两种:断言与反断言。断言操作符为 :,表示匹配具有该属性且值与之相等的用户;反断言操作符为 ~,表示匹配具有该属性且值与之不等的用户。例如,表达式 1:2 可以与上述用户 1 相匹配,但不能与用户 2 相匹配;而表达式 3~1则不能与任何一个用户相匹配。

表达式可以进行逻辑组合,其语法是:<操作符>(表达式 1)(表达式 2)。其中操作符有两种:与(&)和或(|)。如果操作符为与,则当且仅当两个表达式都与某一用户相匹配时,该表达式与该用户相匹配;如果操作符为或,则当且仅当两个表达式中至少有一个与某一用户相匹配时,该表达式与该用户相匹配。例如,表达式 &(1:2)(2:3) 可以与用户 1 相匹配,但不能与用户 2 相匹配;而表达式 |(1:2)(3:1) 则可以与两个用户都相匹配。

形式化地,上述语法用 BNF 范式表示如下:

NON_ZERO_DIGIT =  "1" / "2" / "3" / "4" / 
                  "5" / "6" / "7" / "8" / "9"
DIGIT          =  "0" / NON_ZERO_DIGIT
NUMBER         =  NON_ZERO_DIGIT / (NON_ZERO_DIGIT DIGIT*)
ATTRIBUTE      =  NUMBER
VALUE          =  NUMBER
OPERATOR       =  ":" / "~"
BASE_EXPR      =  ATTRIBUTE OPERATOR VALUE
LOGIC          =  "&" / "|"
EXPR           =  BASE_EXPR / (LOGIC "(" EXPR ")" "(" EXPR ")")

EASY_EXPR      =  BASE_EXPR / 
                  (LOGIC "(" BASE_EXPR ")" "(" BASE_EXPR ")")

输入格式

从标准输入读入数据。

输入的第一行包含一个正整数 n,表示用户的数目。

接下来 n 行,每行包含空格分隔的若干个正整数,第一个正整数表示该用户的 DN,第二个正整数表示该用户具有的属性个数,此后的每两个正整数表示该用户具有的一个属性及其值。这些属性按照属性编号从小到大的顺序给出。

接下来一行包含一个正整数 m,表示匹配表达式的数目。

接下来 m 行,每行包含一个匹配表达式。

输出格式

输出到标准输出。

输出 m 行,每行包含零个或多个正整数,用空格分隔,表示与对应的匹配表达式相匹配的用户的 DN,由小到大排序。

样例输入1

2
1 2 1 2 2 3
2 2 2 3 3 1
4
1:2
3~1
&(1:2)(2:3)
|(1:2)(3:1)

样例输出1

1

1
1 2

样例解释

本组输入是题目描述中的例子。

子任务

对于 20% 的输入,有 1≤n≤100,1≤m≤10,每个用户的属性个数不超过 10,全部属性编号不超过 100,且表达式是原子表达式,即符合 BNF 语法 BASE_EXPR

对于 40% 的输入,有 1≤m≤100,每个用户的属性个数不超过 10,全部属性编号不超过 100,且表达式中至多含有两个原子表达式的逻辑组合,即符合 BNF 语法 EASY_EXPR

对于 70% 的输入,有全部属性编号不超过 500。

对于全部输入,有 1≤n≤2500,1≤m≤500,每个用户的属性个数不超过 500,全部属性编号、属性值和 DN 均不超过 109,每个表达式语句都符合题设语法,且语句字符长度不超过 2000。

时间限制:12.0s

内存限制:1.0GB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:主要是解决表达式嵌套的问题,与栈实现计算器时维护一个符号栈、一个数值栈类似。这里维护了两个栈,一个符号栈op,一个bitset集合栈stk,集合求交、或,由bitest完成。当遇到‘&’或 ‘|’时,将符号压栈;当遇到 ‘)’时,将两个bitset运算为一个bitset。区域部分map乱搞,q[i][j]表示DN = i 用户的j属性值,p(i, j)表示i属性值为j的有哪些用户,has[i]表示i属性有哪些用户,i:j操作时,p[i][j]即为所求;i~j操作时,has[i]内去掉p[i][j]即为所求。to[i]记录了第i个用户对应的DN值,输出时按DN从小到大排序即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int N=2502;
int n,m,sz,id,k,c,d,x,y,num[N],to[N],f[N];
map<int,int>q[N];
map<P,vector<int> >p;
map<int,vector<int> >has;
char s[N],op[N];
bitset<N>stk[N*2],res;
bitset<N>cal(int l,char x,int r){
	bitset<N>ans;
	for(vector<int>::iterator it = p[P(l, r)].begin(); it != p[P(l, r)].end(); ++it){
		ans.set(*it);
	}
	if(x=='~'){
		for(vector<int>::iterator it = has[l].begin(); it != has[l].end(); ++it){
			ans.flip(*it);
		}
	}
	return ans;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d%d",&id,&k);
		to[i]=id;
		for(int j=1;j<=k;++j){
			scanf("%d%d",&x,&y);
			q[i][x]=y;
			has[x].push_back(i);
			p[P(x,y)].push_back(i);
		}
	}
	scanf("%d",&m);
	for(int i=1;i<=m;++i){
		scanf("%s",s);
		sz=strlen(s);
		c=d=0;
		for(int j=0;j<sz;){
			if(s[j]=='&' || s[j]=='|'){
				op[++c]=s[j++];
			}
			else if(s[j]=='('){
				j++;
			}
			else if(s[j]==')'){
				num[c]++;
				if(num[c]==2){
					d--;
					if(op[c]=='&')stk[d]=stk[d]&stk[d+1];
					else stk[d]=stk[d]|stk[d+1];
					num[c--]=0;
				}
				j++;
			}
			else{
				int cur=j,l=0,r=0;
				while(cur<sz && (s[cur]!=':' && s[cur]!='~')){
					l=l*10+(s[cur]-'0');
					cur++;
				}
				char x=s[cur++];
				while(cur<sz && s[cur]!=')'){
					r=r*10+(s[cur]-'0');
					cur++;
				}
				stk[++d]=cal(l,x,r);
				j=cur;
			}
		}
		int e=0;
		for(int j=1;j<=n;++j){
			if(stk[d].test(j)){
				f[++e]=to[j];
			}
		}
		sort(f+1,f+e+1);
		for(int j=1;j<=e;++j){
			printf("%d%c",f[j]," \n"[j==e]);
		}
		if(!e)puts("");
	}
	return 0;
}

 2022-12

试题编号:202212-1

现值计算

问题描述

评估一个长期项目的投资收益,资金的时间价值是一个必须要考虑到的因素。简单来说,假设银行的年利率为 5%,那么当前的 100 元一年后就会变成 105 元,两年后变成 110.25 元。因此,现在收到 100 元比两年后收到 100 元收益更多,两年后再支出 100 元会比立刻支出 100 元更加划算。

基于上述分析,我们使用如下的模型来衡量时间价值:假设银行的年利率为 i,当前(第 0 年)的 x 元就等价于第 k 年的 x×(1+i)k 元;相应的,第 k 年的 x 元的当前价值实际为 x×(1+i)−k 元。

现给出某项目未来 n 年的预计收入支出情况,在将所有款项转换为当前价值后,试计算该项目的总收益。

输入格式

从标准输入读入数据。

输入的第一行包含空格分隔的一个正整数 n 和一个实数 i,分别表示年数和银行年利率。

输入的第二行包含空格分隔的 n+1 个整数,依次表示该项目第 0,1,⋯,n 年的预计收入(正数)或支出(负数)。

输出格式

输出到标准输出中。

输出一个实数,表示该项目在当前价值标准下的总盈利或亏损。

样例输入

2 0.05
-200 100 100

样例输出

-14.059

样例说明

该项目当前支出 200 元,在接下来两年每年收入 100 元。虽然表面看起来收支相抵,但计算当前价值可知总共亏损了约 14.059 元。

子任务

全部的测试数据满足 0<n≤50,0<i<1 且 i 的有效数字不多于 3 位,每年预计收入(正数)或支出(负数)的绝对值不大于 1000。

评分方式

如果你输出的浮点数与参考结果相比,满足绝对误差不大于 0.1,则该测试点满分,否则不得分。

提示

  • C/C++:建议使用 double 类型存储浮点数,并使用 scanf("%lf", &x); 进行输入,printf("%f", x); 进行输出。

  • Python:直接使用 print(x) 进行输出即可。

  • Java:建议使用 double 类型存储浮点数,可以使用 System.out.print(x); 进行输出。

时间限制:1.0s

内存限制:512.0MB

解题思路:根据输入的预计收入或支出计算第k年的x元的当前实际价值。

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

int main(){
	int n;  
	double i;
	cin>>n>>i;
	double all = 0.0; 
	int* nums = new int[n + 1];
	for(int j = 0; j <= n; ++j){
		cin>>nums[j];
		all += nums[j] * pow(1 + i, -j);  // 当前价值 
	}
	cout<<all<<endl;
	return 0; 
}

试题编号:202212-2

训练计划

问题背景

西西艾弗岛荒野求生大赛还有 n 天开幕!

问题描述

为了在大赛中取得好成绩,顿顿准备在 n 天时间内完成“短跑”、“高中物理”以及“核裂变技术”等总共 m 项科目的加强训练。其中第 i 项(1≤i≤m)科目编号为 i,也可简称为科目 i。已知科目 i 耗时 ti 天,即如果从第 a 天开始训练科目 i,那么第 a+ti−1 天就是该项训练的最后一天。

大部分科目的训练可以同时进行,即顿顿在同一天内可以同时进行多项科目的训练,但部分科目之间也存在着依赖关系。如果科目 i 依赖科目 j,那么只能在后者训练结束后,科目 i 才能开始训练。具体来说,如果科目 j 从第 a 天训练到第 a+tj−1 天,那么科目 i 最早只能从第 a+tj 天开始训练。还好,顿顿需要训练的 m 项科目依赖关系并不复杂,每项科目最多只依赖一项别的科目,且满足依赖科目的编号小于自己。那些没有任何依赖的科目,则可以从第 1 天就开始训练。

对于每一项科目,试计算:

1)最早开始时间:该科目最早可以于哪一天开始训练?

2)最晚开始时间:在不耽误参赛的前提下(n 天内完成所有训练),该科目最晚可以从哪一天开始训练?

n 天内完成所有训练,即每一项科目训练的最后一天都要满足 ≤n。需要注意,顿顿如果不能在 n 天内完成全部 m 项科目的训练,就无法参加大赛。这种情况下也就不需要再计算“最晚开始时间”了。

输入格式

从标准输入读入数据。

输入共三行。

输入的第一行包含空格分隔的两个正整数 n 和 m,分别表示距离大赛开幕的天数和训练科目的数量。

输入的第二行包含空格分隔的 m 个整数,其中第 i 个(1≤i≤m)整数 pi 表示科目 i 依赖的科目编号,满足 0≤pi<i;pi=0 表示科目 i 无依赖。

输入的第三行包含空格分隔的 m 个正整数,其中第 i 个(1≤i≤m)数 ti 表示训练科目 i 所需天数,满足 1≤ti≤n。

输出格式

输出到标准输出中。

输出共一行或两行。

输出的第一行包含空格分隔的 m 个正整数,依次表示每项科目的最早开始时间。

如果顿顿可以在 n 天内完成全部 m 项科目的训练,则继续输出第二行,否则输出到此为止。

输出的第二行包含空格分隔的 m 个正整数,依次表示每项科目的最晚开始时间。

样例1输入

10 5
0 0 0 0 0
1 2 3 2 10

样例1输出

1 1 1 1 1
10 9 8 9 1

样例1说明

五项科目间没有依赖关系,都可以从第 1 天就开始训练。

10 天时间恰好可以完成所有科目的训练。其中科目 1 耗时仅 1 天,所以最晚可以拖延到第 10 天再开始训练;而科目 5 耗时 10 天,必须从第 1 天就开始训练。

样例2输入

10 7
0 1 0 3 2 3 0
2 1 6 3 10 4 3

样例2输出

1 3 1 7 4 7 1

样例2说明

七项科目间的依赖关系如图所示,其中仅科目 5 无法在 10 天内完成训练。

样例3输入

10 5
0 1 2 3 4
10 10 10 10 10

样例3输出

1 11 21 31 41

子任务

70% 的测试数据满足:顿顿无法在 n 天内完成全部 m 项科目的训练,此时仅需输出一行“最早开始时间”;

全部的测试数据满足 0<n≤365 且 0<m≤100。

编译环境:Dev-CPP(C++语言C++11标准)

时间限制:1.0s

内存限制:512.0MB
解题思路:在最早开始时间的计算中,每一个科目的最早开始时间依赖于它的前继科目; 而在最晚开始时间的计算中,由于某科目是被别的科目依赖的,所以计算它的最晚开始时间时要考虑依赖它的科目能否如期完成,所以我们做个标记 mark ,如果最早可以完成,则继续分析最晚开始时间; 而将确定每个科目的最晚,需要从最后的科目往前推,因为如果有依赖的科目,需要把依赖该科目的科目所消耗时间算上,如果没有被依赖,那么最晚开始时间 = 最后期限 - 持续时间的时刻;如果有被依赖,那么最晚开始时间 = 依赖它的科目的最晚开始时间中时刻最小的科目 - 本身的持续时间的时刻。

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


int main() {
	int n, m;
	int mark = 1;
	cin>>n>>m;
	vector<int> p(m + 1), t(m + 1), earliest(m + 1), latest(m + 1);
	for(int i = 1; i <= m; i++){
		cin>>p[i];
	}
	for(int i = 1; i <= m; i++){
		cin>>t[i];
	}
	// 确定每个科目的最早时间
	for(int i = 1; i <= m; i++){
		if(p[i] == 0){
			earliest[i] = 1;
		}
		else{
			earliest[i] = earliest[p[i]] + t[p[i]];
		}
		// 根据据所有科目最早开始的时间 判断是否可以完成所有项目 
		if(earliest[i] + t[i] - 1 > n)
		{
			mark = 0;
		 } 
	} 
	// 输出每项科目的最早开始时间
	for(int i = 1; i <= m; i++)
		cout<<earliest[i]<<" "; 
	cout<<endl;
	// 判断 是否可以完成项目
	if(mark == 1){
		// 将确定每个科目的最晚开始时间,从最后的科目往前推,需要把依赖该科目的科目所消耗时间算上
		for(int i = m; i >= 1; i--){
			int temp = 366;
			for(int j = i + 1; j <= m; j++){
				// 寻找是否有依赖该科目的科目
				if(p[j] == i)
					temp = min(temp, latest[j]); 
			}
			//如果没有被依赖,那么最晚开始时间 = 最后期限 - 科目持续时间
			if(temp == 366)
				latest[i] = n - t[i] + 1;
			// 如果有被依赖,那么最晚开始时间 = 依赖它的科目中最小科目的最晚开始时间 - 该科目持续时间 
			else
				latest[i] = temp - t[i]; 
		} 
		// 输出每项科目的最晚开始时间
		for(int i = 1; i <= m; i++)
			cout<<latest[i]<<" "; 
	} 
	return 0;
	
}

2022-09

试题编号:202209-1

如此编码

题目背景

某次测验后,顿顿老师在黑板上留下了一串数字 23333 便飘然而去。凝望着这个神秘数字,小 P 同学不禁陷入了沉思……

题目描述

输入格式

从标准输入读入数据。

输入共两行。

第一行包含用空格分隔的两个整数 n 和 m,分别表示题目数量和顿顿老师的神秘数字。

第二行包含用空格分隔的 n 个整数 a1,a2,⋯,an,依次表示每道选择题的选项数目

输出格式

输出到标准输出。

输出仅一行,包含用空格分隔的 n 个整数 b1,b2,⋯,bn,依次表示每道选择题的正确选项。

样例1输入

15 32767
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2

样例1输出

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

样例2输入

4 0
2 3 2 5

样例2输出

0 0 0 0

样例3输入

7 23333
3 5 20 10 4 3 10

样例3输出

2 2 15 7 3 1 0

样例3解释

子任务

提示

编译环境:Dev-CPP(C++语言C++11标准)

时间限制:1.0s

内存限制:512.0MB

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


int main()
{
	int n, m;
	cin>>n>>m;
	int c = 1, tc = 1;
	vector<int> a(n);
	for(int i = 0; i < n; i++){
		cin>>a[i];
	}
	vector<int> b(n);
	for(int i = 0; i < n; i++){
		tc = c * a[i];
		b[i] = int((m % tc) / c);  // 对应 m % ci / ci-1 
		c = tc;
		cout<<b[i]<<" ";
	}
	return 0;
 } 

试题编号:202209-2

何以包邮?

题目描述

新学期伊始,适逢顿顿书城有购书满 x 元包邮的活动,小 P 同学欣然前往准备买些参考书。
一番浏览后,小 P 初步筛选出 n 本书加入购物车中,其中第 i 本(1≤i≤n)的价格为 ai 元。
考虑到预算有限,在最终付款前小 P 决定再从购物车中删去几本书(也可以不删),使得剩余图书的价格总和 m 在满足包邮条件(m≥x)的前提下最小。

试帮助小 P 计算,最终选购哪些书可以在凑够 x 元包邮的前提下花费最小?

输入格式

从标准输入读入数据。

输入的第一行包含空格分隔的两个正整数 n 和 x,分别表示购物车中图书数量和包邮条件。

接下来输入 n 行,其中第 i 行(1≤i≤n)仅包含一个正整数 ai,表示购物车中第 i 本书的价格。输入数据保证 n 本书的价格总和不小于 x。

输出格式

输出到标准输出。

仅输出一个正整数,表示在满足包邮条件下的最小花费。

样例1输入

4 100
20
90
60
60

样例1输出

110

样例1解释

购买前两本书(20+90)即可包邮且花费最小。

样例2输入

3 30
15
40
30

样例2输出

30

样例2解释

仅购买第三本书恰好可以满足包邮条件。

样例3输入

2 90
50
50

样例3输出

100

样例3解释

必须全部购买才能包邮。

子任务

70% 的测试数据满足:n≤15;

全部的测试数据满足:n≤30,每本书的价格 ai≤10^4 且 x≤a1+a2+⋯+an。

提示

对于 70% 的测试数据,直接枚举所有可能的情况即可。

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路

#include<iostream>
#include<vector>

using namespace std;

int main(){
	int n, x;
	cin>>n>>x;
	vector<int> a(n);
	int sum = 0;
	for(int i = 0; i < n; i++){
		cin>>a[i];
		sum += a[i];
	}
	int target = sum - x;  // 总价-包邮价 
	vector<int> dp(target + 1, 0);
	for(int i = 0; i < n; ++i){
		for(int j = target; j >= a[i]; --j){
			dp[j] = max(dp[j], dp[j - a[i]] + a[i]);
		}
	}
	cout<<sum-dp[target];
	
	return 0;
}

2022-06

题目编号:202206-1

归一化处理

题目背景

在机器学习中,对数据进行归一化处理是一种常用的技术。
将数据从各种各样分布调整为平均值为 0、方差为 1 的标准分布,在很多情况下都可以有效地加速模型的训练

问题描述

输入格式

从标准输入读入数据。

第一行包含一个整数 n,表示待处理的整数个数。

第二行包含空格分隔的 n 个整数,依次表示 a1,a2,⋯,an。

输出格式

输出到标准输出。

输出共 n 行,每行一个浮点数,依次表示按上述方法归一化处理后的数据 f(a1),f(a2),⋯,f(an)。

样例输入

7
-4 293 0 -22 12 654 1000

样例输出

-0.7485510379073613
0.04504284674812264
-0.7378629047806881
-0.7966476369773906
-0.7057985054006686
1.0096468614303775
1.9341703768876082

样例解释

子任务

全部的测试数据保证 n,|ai|≤1000,其中 |ai| 表示 ai 的绝对值。

且输入的 n 个整数 a1,a2,⋯,an 满足:方差 D(a)≥1。

评分方式

如果你输出的每个浮点数与参考结果相比,均满足绝对误差不大于 10−4,则该测试点满分,否则不得分。

提示

  • C/C++:建议使用 double 类型存储浮点数,并使用 printf("%f", x); 进行输出。

  • Python:直接使用 print(x) 进行输出即可。

  • Java:建议使用 double 类型存储浮点数,可以使用 System.out.print(x); 进行输出。

时间限制:500ms

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

int main()
{
	int n;
	cin>>n;
	double sum = 0;
	vector<double> a(n);
	for(int i = 0; i < n; i++)
	{
		cin>>a[i];
		sum += a[i];
	}
	double avg = sum / n;  // 均值 
	double d = 0;
	double res;
	for(int i = 0; i < n; i++){
		d += pow((a[i] - avg), 2);  
	}
	d = sqrt(d / n);  // 方差 开根号 
	for(int i = 0; i < n; i++){
		res = (a[i] - avg) / d;  // f(i) 
		printf("%f\n", res);
	} 
	
	return 0;
}

试题编号:202206-2

寻宝!大冒险!

题目背景

暑假要到了。可惜由于种种原因,小 P 原本的出游计划取消。失望的小 P 只能留在西西艾弗岛上度过一个略显单调的假期……直到……

某天,小 P 获得了一张神秘的藏宝图。

问题描述

输入格式

从标准输入读入数据。

输入的第一行包含空格分隔的三个正整数 n、L 和 S,分别表示西西艾弗岛上树的棵数、绿化图和藏宝图的大小。

由于绿化图尺寸过大,输入数据中仅包含 n 棵树的坐标而非完整的地图;即接下来 n 行每行包含空格分隔的两个整数 x 和 y,表示一棵树的坐标,满足 0≤x,y≤L 且同一坐标不会重复出现。

最后 (S+1) 行输入小 P 手中完整的藏宝图,其中第 i 行(0≤i≤S)包含空格分隔的 (S+1) 个 0 和 1,表示 B[S−i][0]⋯B[S−i][S]。
需要注意,最先输入的是 B[S][0]⋯B[S][S] 一行,B[0][0]⋯B[0][S] 一行最后输入。

输出格式

输出到标准输出。

输出一个整数,表示绿化图中有多少处坐标可以与藏宝图左下角对应,即可能埋藏着顿顿的宝藏。

样例1输入

5 100 2
0 0
1 1
2 2
3 3
4 4
0 0 1
0 1 0
1 0 0

样例1输出

3

样例1解释

绿化图上 (0,0)、(1,1) 和 (2,2) 三处均可能埋有宝藏。

样例2输入

5 4 2
0 0
1 1
2 2
3 3
4 4
0 0 0
0 1 0
1 0 0

样例2输出

0

样例2解释

如果将藏宝图左下角与绿化图 (3,3) 处对应,则藏宝图右上角会超出绿化图边界,对应不成功。

子任务

40% 的测试数据满足:L≤50;

70% 的测试数据满足:L≤2000;

全部的测试数据满足:n≤1000、L≤10^9 且 S≤50。

提示

实际测试数据中不包括答案为 0 的用例。

时间限制:500ms

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>

using namespace std;


int main(){
	int n, L, S;
	cin>>n>>L>>S;
	int A[n][2];
	int B[S + 1][S + 1];
	for(int i = 0; i < n; i++)
	{
		cin>>A[i][0]>>A[i][1];
	}
	int num = 0;
	for(int i = S; i >= 0; i--){
		for(int j = 0; j <= S; j++){
			cin>>B[i][j];  // 最先输入的是 B[S][0]...B[S][S] 一行,B[0][0]...B[0][S] 一行最后输入。
			if(B[i][j] == 1){
				num++;  // 藏宝图中树的数量 
			}
		}
	}
//	cout<<num<<endl;
	int ans = 0;
	for(int i = 0; i < n; i++){
		int p = A[i][0], q = A[i][1];  // x、y坐标
		bool flag = true;
		int temp = 0;
		for(int j = 0; j < n; j++){
			if(A[j][0] - p >= 0 && A[j][0] - p <= S && A[j][1] - q >= 0 && A[j][1] - q <= S){
				temp++;
			}
		} 
		
		if(temp == num){
			for(int j = 0; j < S + 1; j++){
				for(int m = 0; m < S + 1; m++){
					if(p + j > L || q + m > L){  // 检查是否越界 
						flag = false;
						break;
					}
					if(B[j][m] == 0){
						for(int k = 0; k < n; k++){
							if(A[k][0] == p + j && A[k][1] == q + m){
								flag = false;
								break;
							}
						}
					}else{
						for(int k = 0; k < n; k++){
							if(A[k][0] == p + j && A[k][1] == q + m){
								break;
							}
							if(k == n - 1){
								flag = false;
							}
						}
					}
				}
			}
			
			if(flag){
				ans++;
			}
		}
	} 
	cout<<ans;
	return 0; 
} 

2022-03

试题编号:202203-1

未初始化警告

题目背景

一个未经初始化的变量,里面存储的值可能是任意的。因此直接使用未初始化的变量,比如将其赋值给另一个变量,并不符合一般的编程逻辑。代码中出现这种情况,往往是因为遗漏了初始化语句、或是打错了变量名。对代码中使用了未初始化变量的语句进行检查,可以方便地排查出代码中的一些隐秘 Bug。

问题描述

输入格式

输入的第一行包含空格分隔的两个正整数 n、k,分别表示变量的数量和赋值语句的条数。

接下来输入 k 行,其中第 i 行(1≤i≤k)包含空格分隔的两个正整数 xi、yi,表示第 i 条赋值语句。

输出格式

输出一个整数,表示有右值未被初始化问题的赋值语句条数。

样例输入

10 7
1 2
3 3
3 0
3 3
6 2
2 1
8 2

样例输出

3

样例解释

其中第一、二、五条赋值语句右值未被初始化。

子任务

50% 的测试数据满足 0<n,k≤1000;

全部的测试数据满足 0<n,k≤10^5。

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:用一个数组记录赋值语句的右值是否作为左值出现过,若没有则右值未被初始化问题的赋值语句条数加1(0作为常量,特殊处理)。

#include<iostream>
using namespace std;

const int N = 1e5+10; 
bool q[N];  // 记录是否作为左值出现过 
int main()
{
	int n, k;
	cin>>n>>k;
	q[0] = true;  // 常量 
	int x, y;
	int res = 0;
	while(k--){
		cin>>x>>y;
		if(!q[y]){
			res++;
		}
		q[x] = true;
	}
	cout<<res;
	return 0;
 } 

 试题编号:202203-2

出行计划

问题描述

输入格式

输出格式

输出共 m 行,每行一个整数,表示对应查询的答案。

样例输入

6 2 10
5 24
10 24
11 24
34 24
35 24
35 48
1
2

样例输出

3
3

样例解释

时刻 1 做检测,可以满足第三、四、六项出行计划;

时刻 2 做检测,可以满足第四、五、六项出行计划。

子任务

40% 的测试数据满足 0<n,k≤1000、m=1;

70% 的测试数据满足 0<n,m,k≤1000;

全部的测试数据满足 0<n,m,k≤10^5。

时间限制:1.5s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:①暴力解:假设在q时刻做核酸,若q+k ≤ t ≤ q+k+c-1,则该出行计划的核酸检测要求可以得到满足。(会运行超时,只能拿到70分)

差分数组+前缀和:假设在q时刻做核酸,若q+k ≤ t ≤ q+k+c-1,则该出行计划的核酸检测要求可以得到满足。不等式变形可得:t-k-c+1  ≤  q  ≤  t-k,即在符合该不等式的时间段内做核酸即可通行。

差分数组是指在原始数组的基础上构建的一种新数组,用来表示原始数组中相邻元素之间的差值。

性质:

  1. 构建差分数组

    • 原始数组为 arr,差分数组为 diff
    • diff[i] = arr[i] - arr[i - 1],其中 i > 0diff[0] = arr[0]
  2. 更新原始数组

    • 给原始数组中某个区间 [l, r] 增加一个常数 val
      • 在差分数组中更新 diff[l] += val 和 diff[r + 1] -= val
    • 对于这个更新,差分数组的作用是记录了原始数组中区间 [l, r] 每个位置的增量,从而在进行查询时,通过差分数组的前缀和操作,可以快速获取更新后的原始数组的每个位置的值。

例子:

考虑一个原始数组 arr = [3, 2, 5, 6, 1],现在构建差分数组:

  1. 原始数组: arr = [3, 2, 5, 6, 1]
  2. 计算差分数组:
    • diff[0] = arr[0] = 3
    • diff[1] = arr[1] - arr[0] = 2 - 3 = -1
    • diff[2] = arr[2] - arr[1] = 5 - 2 = 3
    • diff[3] = arr[3] - arr[2] = 6 - 5 = 1
    • diff[4] = arr[4] - arr[3] = 1 - 6 = -5
    • 得到差分数组 diff = [3, -1, 3, 1, -5]

如果要对原始数组arr的区间 [1, 3] 进行增加 2 的操作:

  • 对差分数组进行更新:
    • diff[1] += 2diff[4 + 1] -= 2,即 diff[1] += 2diff[5] -= 2
  • 更新后的差分数组为 diff = [3, 1, 3, 1, -7]
  • 对差分数组计算前缀和得[3, 4, 7, 8, 1],等同于对原数组arr的区间[1, 3]进行增加2的操作。

通过差分数组的前缀和操作,可以重新构建出更新后的原始数组。

// 暴力解
#include<iostream>
#include<vector>
using namespace std;

int main()
{
	int n, m, k;
	cin>>n>>m>>k;
	vector<int> t(n), c(n);
	int q;
	
	for(int i = 0; i < n; i++){
		cin>>t[i]>>c[i];
	}
	for(int i = 0; i < m; i++){
		int ans = 0;
		cin>>q;
		int l = q + k;  // 出结果时间
		for(int j = 0; j < n; j++){
			int r = q + k + c[j] - 1;  // 结果过期时间
			if(t[j] >= l && t[j] <= r){
				ans++;
			} 
		}
		cout<<ans<<endl;
	}
	
	return 0;
 } 
// 差分数组+前缀和
#include<iostream>
using namespace std;

const int N = 2e5+10;
int res[N];
int main()
{
	int n, m, k;  // 分别表示出行计划数目、查询个数以及等待核酸检测结果所需时间
	cin>>n>>m>>k;
	while(n--){
		int t, c;  //  t时刻进入某场所,该场所需持有c个单位时间内的核酸检测结果入内
		cin>>t>>c; 
		// 在[l, r]时间段内做核酸,则t时刻可以进入 
		// q+k ≤t≤q+k+c-1  ->  t-k-c+1 ≤q ≤t-k
		int l = max(t- k - c + 1, 0);  // 
		l = min(l, 200000);
		int r = max(0, t - k);
		r = min(r, 200000);
		// 在[l, r] 时间段内能出行的计划个数加1 
		res[l] += 1;
		res[r + 1] -= 1;
	}
	
	// 利用差分计算每个时间能出行的个数 
	for(int i = 1; i < 200001; i++){
		res[i] += res[i - 1];
	}
	for(int i = 0; i < m; i++){
		int q;  // 在q时刻做了核酸检测
		cin>>q;
		cout<<res[q]<<endl;
	}
 } 

2021-12

试题编号:202112-1

序列查询

题目背景

西西艾弗岛的购物中心里店铺林立,商品琳琅满目。为了帮助游客根据自己的预算快速选择心仪的商品,IT 部门决定研发一套商品检索系统,支持对任意给定的预算 x,查询在该预算范围内(≤x)价格最高的商品。如果没有商品符合该预算要求,便向游客推荐可以免费领取的西西艾弗岛定制纪念品。

假设购物中心里有 n 件商品,价格从低到高依次为 A1,A2⋯An,则根据预算 x 检索商品的过程可以抽象为如下序列查询问题。

题目描述

输入格式

从标准输入读入数据。

输入的第一行包含空格分隔的两个正整数 n 和 N。

输入的第二行包含 n 个用空格分隔的整数 A1,A2,⋯,An。

注意 A0 固定为 0,因此输入数据中不包括 A0。

输出格式

输出到标准输出。

仅输出一个整数,表示 sum(A) 的值。

样例1输入

3 10
2 5 8

样例1输出

15

样例1解释

样例2输入

9 10
1 2 3 4 5 6 7 8 9

样例2输出

45

子任务

50% 的测试数据满足 1≤n≤200 且 n<N≤1000;

全部的测试数据满足 1≤n≤200 且 n<N≤10^7。

提示

时间限制:300ms

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:根据提示可得,sum(A)=\sum_{i=1}^{n}(A[i] - A[i - 1]) × i  + (N - A[n]) × n 。

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

int main()
{
	int n, N;
	cin>>n>>N;  // n件商品 
	vector<int> A(n);
	int sum = 0;
	
	for(int i = 0; i < n; i++)
	{
		cin>>A[i];
	}
	for(int i = 1; i < n; i++){
		sum += (A[i] - A[i - 1]) * i;
	}
	if(N > A[n - 1]){
		sum += (N - A[n - 1]) * n;
	}
	cout<<sum;
	return 0;
}

试题编号:202112-2

序列查询新解

题目背景

题目描述

输入格式

从标准输入读入数据。

输入的第一行包含空格分隔的两个正整数 n 和 N。

输入的第二行包含 n 个用空格分隔的整数 A1,A2,⋯,An。

注意 A0 固定为 0,因此输入数据中不包括 A0。

输出格式

输出到标准输出。

仅输出一个整数,表示 error(A) 的值。

样例1输入

3 10
2 5 8

样例1输出

5

样例1解释

样例2输入

9 10
1 2 3 4 5 6 7 8 9

样例2输出

0

样例3输入

2 10
1 3

样例3输出

6

样例3解释

子任务

70% 的测试数据满足 1≤n≤200 且 n<N≤1000;

全部的测试数据满足 1≤n≤10^5 且 n<N≤10^9。

提示

需要注意,输入数据 [A1⋯An] 并不一定均匀分布在 (0,N) 区间,因此总误差 error(A) 可能很大。

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:①暴力解(70分):对于|f(x)-g(x)|的和,我们可以采用动态处理的方式,即每输入一个A[i],就计算一变总和。用a来表示当前的输入,b用来保存上一次a的输入,根据题目可知在[b, a)的范围内,f(i) = i - 1;在[a, N)范围内,f(i) = n。②改进:除了f(x)的取值有一定的规律外,我们观察样例解释可以发现g(x)总是取到一段连续且相同的值,我们只要计算出每一段连续的值的长度,就可以把这一段放在一起处理,以减少循环次数。

// 暴力解(70分)
#include<iostream>
#include<cmath>
using namespace std;


int main()
{
	int n, N;
	cin>>n>>N;
	int r = N / (n + 1);
	long long sum = 0;
//	cout<<r<<endl;
	int a = 0, b;  // a: 数组A的当前值(第一个值为0) b: 前一个值 
	for(int i = 1; i <= n; i++){
		b = a;
		cin>>a;
		for(int j = b; j < a; j++){
			// 区间[b, a)上f(j)的值固定为 i - 1
			sum += abs(j / r - i + 1);  // g(j) - f(j) 
		}
	} 
	// 区间[a, N]
	for(int i = a; i < N; i++){
		// 区间[a, N]上f(i)的值固定为n
		sum += abs(i / r - n);  // g(i) - f(i) 
	} 
	cout<<sum<<endl;
	return 0;	
}
//改进版 (100分)
#include<iostream>
#include<cmath>
using namespace std;

int main()
{
	int n, N;
	cin>>n>>N;
	int r = N / (n + 1);
	long long sum = 0;
	int a = 0, b;  // a: 数组A的当前值(第一个值为0) b: 前一个值 
	int len;  // g(x)取连续相同值的长度 
	for(int i = 1; i <= n; i++){
		b = a;
		cin>>a;
		for(int j = b; j < a; j += len){
			len = (j / r + 1) * r - j;
			// 若计算得到的长度超过区间长度,需进行修正
			if(j < a && j + len > a){
				len = a - j;
			} 
			// 区间[b, a)上f(j)的值固定为 i- 1, g(j)的值固定为 j/ r;
			sum += len * abs(j / r - i + 1);  
		}
	} 
	// 区间[a, N)
	for(int i = a; i < N; i += len){
		len = (i / r + 1) * r - i;
		// 若计算得到的长度超过区间长度,需进行修正
		if(i < N && i + len > N){
			len = N - i;
		}
		// 区间[a, N)上f(i)的值固定为 n, g(j)的值固定为 i/ r
		sum += len * abs(i / r - n);
	} 
	cout<<sum;
	return 0;
}

2021-09

试题编号:202109-1

数组推导

题目描述

输入格式

从标准输入读入数据。

输入的第一行包含一个正整数 n。

输入的第二行包含 n 个用空格分隔的自然数 B1,B2,⋯,Bn。

输出格式

输出到标准输出。

输出共两行。

第一行输出一个整数,表示 sum 的最大值。

第二行输出一个整数,表示 sum 的最小值。

样例1输入

6
0 0 5 5 10 10

样例1输出

30
15

样例1解释

数组 A 的可能取值包括但不限于以下三种情况。

情况一:A=[0,0,5,5,10,10]

情况二:A=[0,0,5,3,10,4]

情况三:A=[0,0,5,0,10,0]

其中第一种情况 sum=30 为最大值,第三种情况 sum=15 为最小值。

样例2输入

7
10 20 30 40 50 60 75

样例2输出

285
285

样例2解释

A=[10,20,30,40,50,60,75] 是唯一可能的取值,所以 sum 的最大、最小值均为 285。

子任务

50% 的测试数据满足数组 B 单调递增,即 0<B1<B2<⋯<Bn<10^5;

全部的测试数据满足 n≤100 且数组 B 单调不降,即 0≤B1≤B2≤⋯≤Bn≤10^5。

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:把输入数组B放入集合set(自动排序,并去除重复元素),然后计算集合s的总和即可得到sum的最小值。至于sum的最大值,只要把B数组的所有元素加起来即可。

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


int main()
{
	int n;
	cin>>n;
	int maxSum = 0, minSum = 0;
	set<int> s;
	vector<int> B(n);
	for(int i = 0; i < n; i++){
		cin>>B[i];  // B单调不降 
		maxSum += B[i];
		s.insert(B[i]);  // 把输入放进set集合,去除重复的输入 
	}
	for(set<int>::iterator it = s.begin(); it != s.end(); ++it)
	{
		minSum += *it;  // 
	}
	
	cout<<maxSum<<endl;
	cout<<minSum;
	return 0;
}

试题编号:202109-2

非零段划分

题目描述

输入格式

从标准输入读入数据。

输入的第一行包含一个正整数 n。

输入的第二行包含 n 个用空格分隔的自然数 A1,A2,⋯,An。

输出格式

输出到标准输出。

仅输出一个整数,表示对数组 A 进行操作后,其非零段个数能达到的最大值。

样例1输入

11
3 1 2 0 0 2 0 4 5 0 2

样例1输出

5

样例1解释

p=2 时,A=[3,0,2,0,0,2,0,4,5,0,2],5 个非零段依次为 [3]、[2]、[2]、[4,5] 和 [2];此时非零段个数达到最大。

样例2输入

14
5 1 20 10 10 10 10 15 10 20 1 5 10 15

样例2输出

4

样例2解释

p=12 时,A=[0,0,20,0,0,0,0,15,0,20,0,0,0,15],4 个非零段依次为 [20]、[15]、[20] 和 [15];此时非零段个数达到最大。

样例3输入

3
1 0 0

样例3输出

1

样例3解释

p=1 时,A=[1,0,0],此时仅有 1 个非零段 [1],非零段个数达到最大。

样例4输入

3
0 0 0

样例4输出

0

样例4解释

无论 p 取何值,A 都不含有非零段,故非零段个数至多为 0。

子任务

70% 的测试数据满足 n≤1000;

全部的测试数据满足 n≤5×10^5,且数组 A 中的每一个数均不超过 10^4。

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:在数组A的前后分别插入1个0,第1种情况:若当前位置变为0,且当前数字左右两边都不为0,那么会增加一个非零段;第二种情况:若当前位置变为0,且左右两边都是0,则会减少一个非零段;第三种情况:若当前位置变为0,左边和右边只存在一个非0数字,那么不会影响非零段个数。

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

int main() {
    int n;
    cin >> n;
    vector<int> v;
    int num;
    map<int, vector<int> > m;
    v.push_back(0);
    for (int i = 0; i < n; i++) {
        cin >> num;
        v.push_back(num);
    }
    v.push_back(0);

    int cnt = 0;
    bool f = true;

    for (int i = 0; i < v.size(); i++) {
        if (v[i])  // 不等0 
            m[v[i]].push_back(i);
        if (v[i]) {
            f = false;
        } else {
            if (!f)  // f = false 
                cnt++;
            f = true;
        }
    }
    int ret = cnt;
    for (map<int, vector<int> >::iterator it = m.begin(); it != m.end(); ++it) {
        for (vector<int>::iterator iter = it->second.begin(); iter != it->second.end(); ++iter) {
            if (v[(*iter) - 1] && v[(*iter) + 1]) { // 左右两个都不为0 
                cnt++;
            } else if (!v[(*iter) - 1] && !v[(*iter) + 1]) {  // 左右两个都为0 
                cnt--;
            }
            v[*iter] = 0;
        }
        ret = max(ret, cnt);
    }
    cout << ret;

    return 0;
}

2021-04

试题编号:202104-1

灰度直方图

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:输入时对应的A[i][j]的h值加1。

#include<iostream>
using namespace std;

int h[256];
int main()
{
	int n, m, L;
	cin>>n>>m>>L;
	int A[n][m];

	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			cin>>A[i][j];
			h[A[i][j]]++;
		}
	}
	
	for(int i = 0; i < L; i++){
		cout<<h[i]<<" ";
	}
	return 0;
 } 

试题编号:202104-2

领域均值

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:差分+前缀和思想。创建一个差分数组B,在输入数组A时,对输入的每一个值A[i][j],先进行以下预处理:确定A[i][j]的领域范围,对于范围内的每一个值,在进行后续领域求和时,都要加上A[i][j],所以预先将该领域内的所有元素都加上A[i][j]。差分的思想:对于领域内的每一行,将第一个元素加上A[i][j],最后一个元素的后一个元素减去A[i][j]。输入结束后,再将差分数组B求前缀和,这时,数组B的每一个值就是该位置原来的元素领域求和的结果。

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

int B[1000][1000];
int main(){
	int n, L, r, t;
	cin>>n>>L>>r>>t;
	int A[n][n];
	int x1, x2, y1, y2;  // 用来确定领域的范围 
	int count = 0;  // 记录个数 
	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			cin>>A[i][j];
			x1 = max(i - r, 0);
			x2 = min(i + r, n - 1);
			y1 = max(j - r, 0);
			y2 = min(j + r, n - 1);
			// 差分数组
			for(int k = y1; k <= y2; k++){  // 给原始数组B中区间[x1, x2]增加一个常数A[i][j]
				B[x1][k] += A[i][j]; 
				B[x2 + 1][k] -= A[i][j];
			} 
		}
	}
	// 还原  (前缀和) 
	for(int i = 0; i < n; i++){
		for(int j = 1; j < n; j++){
			B[j][i] = B[j][i] + B[j - 1][i];
		}
	}
	float aver, len;
	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			x1 = max(i - r, 0);
			x2 = min(i + r, n - 1);
			y1 = max(j - r, 0);
			y2 = min(j + r, n - 1);
			len = (x2 -x1 + 1) * (y2 - y1 + 1);  //领域的元素个数
			// 领域内所有元素的均值
			aver = B[i][j] / len;
			if(aver <= t)
			{
				count++;
			 } 
		}
	}
	
	cout<<count;
	return 0;
}

2020-12

试题编号:202012-1

期末预测之安全指数

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:按照题目去做就好,挺简单的

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

int main()
{
	int n;
	cin>>n;
	int w, s;
	int sum = 0;
	for(int i = 0; i < n; i++)
	{
		cin>>w>>s;
		sum += w * s;
	}
	cout<<max(0, sum);
	return 0;
}

试题编号:202012-2

期末预测之最佳阈值

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:要求找到估计准确数最大的阈值,估计准确数包括两个方面:一是小于该值的挂科数,二是大于等于该值的未挂科数。首先需要对数据进行预处理:安装阈值从小到达进行排序,然后运行前缀和求出来所有的未挂科数量。对每一个1~m的所有阈值进行判断准确数找到最大的阈值即可。

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

int main()
{
	int m;
	cin>>m;
	int s[100005];
	pair<int, int> p[m];
	for(int i = 0; i < m; i++)
	{
		cin>>p[i].first>>p[i].second;
	}
	sort(p, p + m); // 按第一维从小到大排序 
	for(int i = 1; i <= m; i++){
		s[i] = s[i - 1] + p[i].second;  // 前缀和 
	}
	int l = 0, maxn = 0, cnt = 0, ymax;
	for(int i = 0; i < m; i++){
		l = i;
		cnt = 0;
		while(l >= 0 && p[l].first >= p[i].first){
			l--;
		}
		cnt += s[m] - s[l] + l - s[l];
		if(maxn <= cnt){
			maxn = cnt;
			ymax = p[i].first;
		}
	}
	cout<<ymax<<endl;
	return 0;
}

2020-09

试题编号:202009-1

称检测点查询

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:利用pair数组记录每个检测点离市民(X, Y)位置的距离,并记录检测点的编号。对pair数组的第一维进行排序,输出前三个pair数组记录的第二维即可。

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

int main()
{
	int n, X, Y, a, b;
	cin>>n>>X>>Y;
	int d = 0;
	pair<int, int> p[n];
	for(int i = 0; i < n; i++){
		cin>>a>>b;
		d = (X - a) * (X - a) + (Y - b) * (Y - b);
		p[i].first=d;
		p[i].second = i + 1;
	}
	sort(p, p+n);
	for(int i = 0; i < 3; i++){
		cout<<p[i].second<<endl;
	}
	return 0;
}

试题编号:202009-2

风险人群筛查

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:用f1记录是否连续位于高位区域内(包括边界),flag记录连续位于危险区域的次数,fmax记录连续位于危险区域的最大值。num记录经过高危区域的人数,num2记录曾在高危区域逗留的人。经过高危区域的人数又等于num+num2。

#include<iostream>
using namespace std;


int main()
{
	int n, k, t, xl, yd, xr, yu;
	cin>>n>>k>>t>>xl>>yd>>xr>>yu;
	int x, y;
	int num = 0, num2 = 0;  //num经过, num2逗留 
	int flag = 0, f1 = 0, fmax = 0;  // flag是一次连续经过几个点,f1判断是否连续,fmax记录连续经过的点中的最大值 
	for(int i = 0; i < n; i++){
		flag = 0;
		f1 = 0;
		fmax = 0;
		for(int j = 0; j < t; j++){
			cin>>x>>y;
			if(xl <= x && x <= xr && yd <= y && y <= yu){  // 位于区域内(包括边界) 
				if(f1 == j - 1){
					flag++;  // 连续位于边界内 
				}else{
					flag=1;
				}
				f1 = j;
			}
			
			if(fmax < flag){
				fmax = flag;
			}
		}
		
		if(fmax >= k){
			num2++;
		}else if(fmax > 0){
			num++;
		}
	}
	cout<<num + num2<<"\n"<<num2;
	return 0;
}

2020-06

试题编号:202006-1

线性分类器

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)
真题网站计算机软件能力认证考试系统

#include<iostream>
using namespace std;

const int N = 1001;
char up[N], down[N];
int main()
{
	int n, m;
	cin>>n>>m;
	int x[n], y[n];
	char type[n];
	int c, a, b;
	for(int i = 0; i < n; i++){
		cin>>x[i]>>y[i]>>type[i];
	}
	int j;
	for(int i = 0; i < m; i++){
		cin>>c>>a>>b;
		for(j = 0; j < n; j++){
			if(type[j] == 'A')  // 先判断类型,再判断其相对直线的位置。假如有一个A在直线上方,那么此时直线下方只能是B类型 
			{
				if((c + a * x[j] + b * y[j]) > 0){  // 在直线上方 
					up[j] = type[j];
					down[j] = 'B';
				}else if((c + a * x[j] + b * y[j]) < 0)  // 在直线下方
				{
					down[j] = type[j];
					up[j] = 'B'; 
				 } 
			}
			else if(type[j] == 'B'){
				if((c + a * x[j] + b * y[j]) > 0){  // 在直线上方 
					up[j] = type[j];
					down[j] = 'A';
				}else if((c + a * x[j] + b * y[j]) < 0)  // 在直线下方
				{
					down[j] = type[j];
					up[j] = 'A'; 
				 } 
			} 
		}
		
		for(j = 1; j < n; j++)  // 判断其中一个数组是否都是同一种类型 
		{
			if(up[j - 1] != up[j])
			{
				cout<<"No"<<endl;
				break;
			 } else if(j == n - 1)
			 {
			 	cout<<"Yes"<<endl;
			 }
		}
	}
	
 } 

试题编号:202006-2

稀疏向量

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:当两个向量的index相同时将他们的value之相乘。

#include<iostream>
using namespace std;

int main()
{
	int n, a, b;
	cin>>n>>a>>b;
	pair<int, int> u[a], v[b];
	long long sum = 0;  // 结果可能会很大,不取long long会数据溢出
	for(int i = 0; i < a; i++){
		cin>>u[i].first>>u[i].second;
	}

	for(int i = 0; i < b; i++){
		cin>>v[i].first>>v[i].second;
	}
	
	int i = 0, j = 0;
	while(i < a && j < b)
	{
		if(u[i].first == v[j].first){  // 当两个index相等
			sum += u[i].second * v[j].second;
			i++;
			j++;
		}else if(u[i].first > v[j].first){
			j++;
		}else{
			i++;
		}
	}
	cout<<sum;
	return 0;
}

2019-12

试题编号:201912-1

报数

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int times[4] = {0, 0, 0, 0};
	int n;
	cin>>n;
	int a = 0;
	for(int i = 1; i <= n; i++)
	{
		int j = (i - 1) % 4;  // 确定是甲乙丙丁中的哪个人,因为下标从0开始 
		if(i % 7 == 0){
			times[j]++;
			n++;
			continue;
		} 
		int temp = i;
		while(temp / 10 > 0 || temp % 10 > 0)  // 遍历i中的每一个数字,判断是否有7 
		{
			if(temp % 10 == 7){
				times[j]++;
				n++;
				break;
			}
			temp = temp / 10;
		}
	}
	for(int i = 0; i < 4; i++){
		cout<<times[i]<<endl;
	}
	return 0;
}

试题编号:201912-2

回收站选址

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:先找到符合上下左右均有邻居的位置,再看看其对角位置有多少个位置存在垃圾。

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


int main()
{
	int n;
	cin>>n;
	set<pair<int, int> > location;  // 自动排序
	while(n){
		int x, y;
		cin>>x>>y;
		location.insert(make_pair(x, y));
		--n;
	}
	int score[5] = {0};
	for(set<pair<int, int> >::iterator it = location.begin(); it != location.end(); ++it){
		pair<int, int> p = *it;
        // 上下左右四个位置
		pair<int, int> p1(p.first - 1, p.second);
		pair<int, int> p2(p.first + 1, p.second);
		pair<int, int> p3(p.first, p.second - 1);
		pair<int, int> p4(p.first, p.second + 1);
		// 对角的四个位置
		pair<int, int> p5(p.first - 1, p.second - 1);
		pair<int, int> p6(p.first + 1, p.second + 1);
		pair<int, int> p7(p.first + 1, p.second - 1);
		pair<int, int> p8(p.first - 1, p.second + 1);
		int s = 0;
		if(location.find(p1) != location.end() && location.find(p2) != location.end() && location.find(p3) != location.end() && location.find(p4) != location.end())
		{
			if(location.find(p5) != location.end()){
				++s;
			}
			if(location.find(p6) != location.end()){
				++s;
			}
			if(location.find(p7) != location.end()){
				++s;
			}
			if(location.find(p8) != location.end()){
				++s;
			}
			++score[s];
		}
	}
	for(int i = 0; i < 5; i++){
		cout<<score[i]<<endl;
	}
	return 0;
 } 

2019-09

试题编号:201909-1

小明种苹果

时间限制:2.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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


int main()
{
	int N, M;
	cin>>N>>M;
	
	int T = 0, K = 0, P = 0;
	int q = 0;
	int a;
	for(int i = 0; i < N; i++)
	{
		q = 0;
		for(int j = 0; j < M +1; j++){
			cin>>a;
			T += a;
			if(j > 0){
				q += a;
			}
		}
		if(P  > q){
			P = q;
			K = i + 1;
		}
	}
	P = 0 - P;
	cout<<T<<" "<<K<<" "<<P;
	return 0;
}

试题编号:201909-2

小明种苹果(续)

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;


int main()
{
	int n;
	cin>>n;
	int ans[n + 2] = {0};
	int m;
	int sum = 0;
	int D = 0, E = 0;
	for(int i = 0; i < n; i++){
		cin>>m;
		int b[m];
		int sumij = 0;
		for(int j = 0; j < m; j++){
			cin>>b[j];
			sumij = b[0];  // 初始时每棵树的苹果数
		}
		for(int j = 0; j < m; j++){
			if(b[j] <= 0){  // 疏果
				sumij += b[j];
			}else{  // 统计
				if(sumij != b[j] && ans[i + 1] == 0){
					D++;
					ans[i + 1] = 1;
				}
				sumij = b[j];  // 更新数量
			}
		}
		sum += sumij;
	} 
	ans[0] = ans[n];
	ans[n + 1] = ans[1];
	for(int i = 0; i <= n - 1; i++){  // 相邻的都有掉落
		if(ans[i] == 1 && ans[i + 1] == 1 && ans[i + 2] == 1){
			E++;
		}
	}
	
	cout<<sum<<" "<<D<<" "<<E;
	return 0;
}

2019-03

试题编号:201903-1

小中大

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int n;
	cin>>n;
	int max, min;
	int a[n];
	for(int i = 0; i < n; i++){
		cin>>a[i];
	}
	if(a[0] > a[n - 1]){
		max = a[0];
		min = a[n - 1];
	}else{
		max = a[n - 1];
		min = a[0];
	}
	if(n % 2 == 1){
		printf("%d %d %d", max, a[n / 2], min);
	}else{
		if((a[n / 2 - 1] + a[n / 2]) % 2 == 0){
			printf("%d %d %d", max, (a[n / 2 - 1] + a[n / 2]) / 2, min);
		}else{
			printf("%d %.1f %d", max, (a[n / 2 - 1] + a[n / 2]) / 2.0, min);
		}
	}
	return 0;
}

试题编号:201903-2

二十四点

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

stack<int> num;  // 存放数字 
stack<char> op;  // 存放符合 

void calculate(char x){
	int n1 = num.top();
	num.pop();
	int n2 = num.top();
	num.pop();
	switch(x){
		case '+':
			num.push(n1 + n2);
			break;
		case 'x':
			num.push(n1 * n2);
			break;
		case '/':
			num.push(n2 / n1);
			break;
	}
}


int main()
{
	int n;
	cin>>n;
	string s;
	while(n--){
		while(!num.empty()) num.pop();
		while(!op.empty()) op.pop(); 
		cin>>s;
		for(int i = 0; i < 7; i++){
			if(s[i] >= '1' && s[i] <= '9'){
				num.push(s[i] - '0');
			}else if(s[i] == 'x' || s[i] == '/'){
				// 乘号或除号
				num.push(s[i + 1] - '0');
				calculate(s[i]);
				i++; 
			}else if(s[i] == '-'){
				op.push('+');
				num.push(-(s[i + 1] - '0'));
				i++;
			}else{
				op.push(s[i]);
			}
		}
		while(!op.empty()){
			calculate(op.top());
			op.pop();
		}
		num.top() == 24 ? cout<<"Yes"<<endl : cout<<"No"<<endl;
	}
	return 0;
}

2018-12

试题编号:201812-1

小明上学

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int r, y, g;
	cin>>r>>y>>g;
	int n;
	cin>>n;
	int sum = 0;
	// 红灯->绿灯->黄灯 
	for(int i = 0; i < n; i++)
	{
		int k, t;
		cin>>k>>t;
		if(k == 0){  // 经过了一段路 
			sum += t;
		}
		else if(k == 1)  // 红灯 
		{
			sum += t; 
		}else if(k == 2) // 黄灯
		{
			sum += t + r; 
		 } 
	}
	cout<<sum;
	return 0; 
}

试题编号:201812-2

小明放学

时间限制:1.0s

内存限制:512.0MB

编译环境:Dev-CPP(C++语言C++11标准)

出处:csp-小明放学(c++)_c++问题描述:一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各-CSDN博客

#include<bits/stdc++.h>
using namespace std;
int main(void){
	long long int r,y,g;//红绿灯秒数
	cin>>r>>y>>g;
	long long int n;
	long long int num=0;
	cin>>n;
	int status,tim;
	while(n--){
		cin>>status>>tim;
		switch(status){
			case 0:num += tim; break;
			case 1://红灯
			if(tim >= num) num = tim; 
			else{
				long long int temp = 0;//设置标签  红-》绿-》黄 
				temp=(num - tim + r)%(r + y + g);
				if(temp < r + 1){//红灯区间 
					num += r - temp;
				}
				else if(temp > r + g){//黄灯区间
				num += r + g + y - temp + r;//黄灯完还要等一整个红灯; 
				}
				else ;
			} break;
		    case 2://黄灯 黄-》红-》绿 
		    if(tim >= num)	
			{
			num = tim + r;
			}
			else{
				long long int temp = 0;
				temp = (num - tim + y) % (r + y + g);
				if(temp < y + 1){
					num += y - temp + r;
				}else if(temp > r + y){
					//标签在绿灯区 
				}
				else num += r + y - temp; //标签在红灯区 
			} break;
			case 3:
			if(tim > num);
			else{
				long long int temp = 0;
				temp = (num + g - tim) % (r + y + g);
				if(temp < g + 1);//标签落在绿灯区间 
				else if(temp > y + g){//标签落在红灯区间 
					num += r + g + y - temp;
				} else{//标签落在黄灯区间
				num += g + y - temp + r; 
				}
			} 
		}
		}
			cout<<num<<endl;
	return 0; 
	}


2018-09

试题编号:201809-1

卖菜

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int n;
	cin>>n;
	int num[n];
	int num2[n];
	for(int i = 0; i < n; i++){
		cin>>num[i];
	}
	for(int i = 0; i < n; i++){
		if(i == 0){
			num2[i] = (num[i] + num[i + 1]) / 2;
		}else if(i == n - 1){
			num2[i] = (num[i] + num[i - 1]) / 2;
		}else{
			num2[i] = (num[i - 1] + num[i] + num[i + 1]) / 3;
		}
		cout<<num2[i]<<" ";
	}
	return 0;
}

试题编号:201809-2

买菜

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int n;
	cin>>n;
	int h[2][n], w[2][n];
	long long sum = 0;
	int start, end;
	for(int i = 0; i < n; i++){
		cin>>h[0][i]>>h[1][i];
	}
	for(int i = 0; i < n; i++){
		cin>>w[0][i]>>w[1][i];
	}
	for(int i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			if(w[0][j] > h[1][i] || w[1][j] < h[0][i])	continue;  
			start = h[0][i] > w[0][j] ? h[0][i]: w[0][j];  // 开始时间为较大者 
			end = h[1][i] > w[1][j] ? w[1][j]: h[1][i];  // 结束时间为较小者 
			sum += end - start;
		}
	}
	cout<<sum;
	return 0;
}

2018-03

试题编号:201803-1

跳一跳

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:主要是处理各种可能的情况。

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


int main()
{
	vector<int> a, temp;
	int b, sum = 0;
	while(cin>>b){
		a.push_back(b);
		if(cin.get() == '\n'){
			break;
		}
	}
	for(int i = 0; i < a.size(); i++){
		if(i == 0){
			if(a[i] == 2){
				sum += a[i];
				temp.push_back(2);
			} 
			else{
				sum += a[i];
				temp.push_back(1);
			}
		}else{
			if(a[i] == 1){
				sum += a[i];
				temp.push_back(1);
			}else if(a[i - 1] == 2 && a[i] == 2){
				sum += 2 + temp[i - 1];
				temp.push_back(2 + temp[i - 1]);
			}else{
				sum += a[i];
				temp.push_back(2);
			}
		}
	}
	cout<<sum;
	return 0;
	
 } 

试题编号:201803-2

碰撞的小球

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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


int main()
{
	int n, L, t;
	cin>>n>>L>>t;
	vector<int> positions(n);
	for(int i = 0; i < n; i++){
		cin>>positions[i];
	}
	vector<int> velocities(n, 1);  // 记录速度的大小和方向 
	
	for(int time = 0; time < t; time++){
		vector<int> next_positions = positions; 
		vector<int> next_velocities = velocities; 
		for(int j = 0; j < n; j++){
			next_positions[j] += velocities[j];
			if(next_positions[j] == 0 || next_positions[j] == L){
				next_velocities[j] *= -1;  // 撞墙反向 
			}
		}
		
		for(int i = 0; i < n; i++){
			for(int j = i + 1; j < n; j++){
				if(next_positions[i] == next_positions[j])  // 碰撞
				{
					next_velocities[i] *= -1;  // 反向
					next_velocities[j] *= -1; 
				 } 
			}
		} 
		positions = next_positions;  // 更新位置和速度 
		velocities = next_velocities;
	}
	for(int i = 0; i < n; i++){
		cout<<positions[i]<<" ";
	}

	return 0;
}

2017-12

试题编号:201712-1

最小差值

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

int main()
{
	int n;
	cin>>n;
	vector<int> a(n);
	for(int i = 0; i < n; i++){
		cin>>a[i];
	}
	sort(a.begin(), a.end());
	int min = 10000;
	for(int i = 1; i < n; i++){
		int res;
		res = abs(a[i] - a[i - 1]);
		if(res < min){
			min = res;
		}
	}
	cout<<min;
	return 0;
}

试题编号:201712-2

游戏

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:用num记录报数的数值,而不是更改a[i]的值。

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

int main()
{
	int n, k;
	cin>>n>>k;
	vector<int> a(n, 0);  // 全部元素初始化为0 
	int temp = n;
	int num = 1;  // 报数 
	int index = 0;  // 小朋友的下标 
	while(temp > 1){
		if(a[index] == 0){
			if(num % k == 0 || num % 10 == k){
				a[index] = 1;  // 标记为出局 
				temp--;  // 人数减1 
			}
			num++;
		}
		index = (index + 1) % n;  // index + 1 
	}
	for(int i = 0; i < n; i++){
		if(a[i] == 0){
			cout<<i + 1;
		}
	}
	return 0;
}

2017-09

试题编号:201709-1

打酱油

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int N;
	cin>>N;
	int sum = 0;
	if(N % 50 == 0){
		sum = N / 10 + (N / 50) * 2;
	}else{
		if(N % 50 >= 30){
			sum = N / 10 + (N / 50) * 2 + 1;
		}else{
			sum = N / 10 + 2 * N / 50;
		}
	}
	cout<<sum;
	return 0;
 } 

试题编号:201709-2

公共钥匙盒

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:使用优先队列priority_queue。将同一教室的借钥匙和还钥匙分开为两次操作act,以时间先后对全部操作diary[]进行排序,依据排序靠前的操作对钥匙盒keys[]的状态进行模拟。-

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

typedef struct Act{
	int room;  // 教室编号
	bool state;  // true为归还,false为取用
	int time;  // 动作发生时间  
	
}act;

struct tmp1{
	bool operator()(act a, act b){
		if(a.time == b.time){
			if(a.state == b.state){
				return a.room > b.room;  // 同一状态的两个操作,教室编号越小,优先级越高 
			}else{
				return a.state < b.state;  // 同一时间的两个操作,还比借优先,大根堆 
			} 
		}else{
			return a.time > b.time;  // 时间越早(小),优先级越高,小根堆 
		}
	}
};

int main()
{
	int N, K;
	cin>>N>>K;
	priority_queue<act, vector<act>, tmp1> diary;
	int w, s, c;
	int keys[N + 1];
	for(int i = 1; i <= N; i++){
		keys[i] = i;  // 初始化 
	} 
	for(int i = 0; i < K; i++){
		cin>>w>>s>>c;
		diary.push({w, false, s});  // 借钥匙
		diary.push({w, true, s + c});  // 还钥匙 
	} 
	act p;
	while(!diary.empty()){
		p = diary.top();
		diary.pop();
		if(p.state){  // 归还
			for(int i = 1; i <= N; i++){
				if(keys[i] == 0){
					keys[i] = p.room;
					break;
				}
			}
		}else{  // 取用
			for(int i = 1; i <= N; i++){
				if(keys[i] == p.room){
					keys[i] = 0;
					break;
				}
			}
		}
	} 
	for(int i = 1; i <= N; i++){
		cout<<keys[i]<<" ";
	}
	return 0;
}

2017-03

试题编号:201703-1

分蛋糕

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

int main()
{
	int n, k;
	cin>>n>>k;
	vector<int> a(n);
	int num = 0;  // 记录分到蛋糕的朋友的个数 
	for(int i = 0; i < n; i++){
		cin>>a[i];
	}
	int sum = 0;
	for(int i = 0; i < n; i++){
		sum += a[i];
		if(sum >= k){
			num++;
			sum = 0;
		}
	}
	// 如果最后一位朋友分到了蛋糕但重量不足k,需要再加一位朋友 
	if(sum > 0){
		num++;
	}
	cout<<num;
	return 0; 
}

试题编号:201703-2

学生排队

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>

using namespace std;

int main()
{
	int n;
	cin>>n;
	int a[n + 1];
	for(int i = 0; i < n; i++){
		a[i] = i + 1;
	}
	int m;
	cin>>m;
	for(int i = 0; i < m; i++){
		int p, q;
		cin>>p>>q;
		// 先找到学号p学生的位置
		int j;
		for(j = 0; j < n; j++){
			if(a[j] == p){
				break;
			}
		} 
		if(q > 0){  // 后移 
			for(int k = j; k < j + q; k++){  // 区间元素向前移 
				a[k] = a[k + 1]; 
			} 
			a[j + q] = p;
		}else if(q < 0)  // 前移
		{
			for(int k = j; k > j + q; k--){  // 区间元素后移 
				a[k] = a[k - 1];
			} 
			a[j + q] = p;
		 } 
	}
	for(int i = 0; i < n; i++){
		cout<<a[i]<<" ";
	}
	return 0;
}

2016-12

试题编号:201612-1

中间数

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

int main()
{
	int n;
	cin>>n;
	vector<int> a(n);
	for(int i = 0; i < n; i++){
		cin>>a[i];
	}
	sort(a.begin(), a.end());
	int small = 0, big = 0;
	int midIndex = n / 2;
	int midValue = a[midIndex];
	for(int i = 0; i < n; i++){
		if(a[i] < midValue){
			small++;
		}else if(a[i] > midValue){
			big++;
		}
	}
	if(small == big){
		cout<<midValue;
	}else{
		cout<<"-1";
	}
	return 0;
}

试题编号:201612-2

工资计算

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int T;  // 税后所得 
	cin>>T;
	
	float tax[7] = {0.97,0.9,0.8,0.75,0.7,0.65,0.55};  // 1-税率 
	int flag[7] = {3500,3500+1500,3500+4500,3500+9000,3500+35000,3500+55000,3500+80000};  // 税基 
	int num[7];
	num[0] = 3500;  // 起征点 
	for(int i = 1; i < 7; i++){
		num[i] = num[i - 1] + (flag[i] - flag[i - 1]) * tax[i - 1];  // 各个段税后所得 
	}

	int i = 0;
	while(i < 7){
		if(T < num[i]){  // 查找区间 
			break;
		}
		i++;
	}
	if(i == 0){
		cout<<T;
	}else{
		cout<<flag[i - 1] + (T - num[i - 1]) / tax[i - 1];  // 上一falg加上下一段税前 
	}
	return 0;
}

2016-09

试题编号:201609-1

最大波动

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

int main()
{
	int n;
	cin>>n;
	int a[n];
	int m = 0;
	for(int i = 0; i < n; i++){
		cin>>a[i];
		if(i > 0){
			m = max(abs(a[i] - a[i - 1]), m);
		}
	}
	cout<<m;
	return 0;
}

试题编号:201609-2

火车购票

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;


int main()
{
	int n;
	cin>>n;
	int seat[20]= {};
	for(int i = 0; i < 20; i++){
		seat[i] = 5;  // 初始每排余票数量 
	}
	while(n--){
		int p;
		cin>>p;
		int i = 0;
		while(i < 20 && p > seat[i])  // 每排的剩余数量小于购票数 
			i++;
		if(i < 20){  // 安排在同一排编号相邻的座位
			int start = i * 5 + 5 - seat[i] + 1;
			seat[i] -= p;
			for(int i = 0; i < p; i++){
				cout<<start + i;
				if(i < p - 1)	cout<<" ";
			}
		}else{
			for(int i = 0; i < 20 && p > 0; i++){  // 安排在编号最小的几个空座位中 
				if(seat[i] == 0)	continue;
				int start = i * 5 + 5 - seat[i] + 1;
				int j = 0;
				while(j < seat[i] && j < p){
					cout<<start + j;
					if(p > 0)	cout<<" ";
					j++;
				}
				p -= j;
				seat[i] -= j;
			}
		}
		cout<<endl;
	}
	
	return 0;
}

2016-04

试题编号:201604-1

折点计数

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int n, count = 0;
	cin>>n;
	int a[n];
	for(int i = 0; i < n; i++){
		cin>>a[i];
	}
	for(int i = 1; i < n - 1; i++){
		if(a[i] > a[i - 1] && a[i] > a[i + 1]){
			count++;
//			cout<<a[i]<<endl;
		}else if(a[i] < a[i - 1] && a[i] < a[i + 1]){
			count++;
//			cout<<a[i]<<endl;
		}
	}
	cout<<count;
	return 0;
}

试题编号:201604-2

俄罗斯方块

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main(){
	bool a[20][10];
	bool b[4][4];
	int c;
	for(int i = 1; i <= 15; i++){
		for(int j = 1; j <= 10; j++){
			cin>>a[i][j];
		}
	}
	for(int i = 0; i < 4; i++){
		for(int j = 0; j < 4; j++){
			cin>>b[i][j];
		}
	}
	cin>>c;
	
	for(int r = 1; ; r++){
		bool st = false;
		for(int i = 0; i < 4; i++){
			for(int j = 0; j < 4; j++){
				if(b[i][j] && a[r + i][c + j]){
					st = true;
					break;
				}
			}
			if(st)	break;
		}
		if(st){  // 找到可以放置形状的位置,即找到a数组中的一部分与b数组重叠的位置,放置形状在该位置上 
			r--;  
			for(int i = 0; i < 4; i++){
				for(int j = 0; j < 4; j++){
					if(b[i][j]){
						a[r + i][c + j] = b[i][j];
					}
				}
			}
			break;
		}
	}
	
	for(int i = 1; i <= 15; i++){
		for(int j = 1; j <= 10; j++){
			cout<<a[i][j]<<" ";
		}
		cout<<endl;
	}
	return 0;
}

2015-12

试题编号:201512-1

数位之和

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	long long n;
	cin>>n;
	long long sum = 0;
	while(n){
		sum += n % 10;
		n = n / 10;
	}
	cout<<sum;
	return 0;
}

试题编号:201512-2

消除类游戏

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;
bool b[30][30];
int main()
{
	int n, m;
	cin>>n>>m;
	int a[n][m];
	
	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			cin>>a[i][j];
		}
	}
	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			int start = i, end = i, start2 = j, end2 = j;
			while(start >= 0 && a[start][j] == a[i][j]) start--;
			while(end < n && a[end][j] == a[i][j])	end++;  // 行 
			
			while(start2 >= 0 && a[i][start2] == a[i][j]) start2--;
			while(end2 < m && a[i][end2] == a[i][j])	end2++;  // 列 
			
			if((end - start) >= 4 || (end2 - start2) >= 4){  // 对每一个被消除的位置,修改标志位 
				b[i][j] = true;
			}
		}
	}
	for(int i = 0; i < n; i++){
		for(int j = 0; j < m; j++){
			if(b[i][j]){
				cout<<0<<" ";
			}else{
				cout<<a[i][j]<<" ";
			}
		}
		cout<<endl;
	}
	return 0;
}

2015-09

试题编号:201509-1

数列分段

问题描述

  给定一个整数数列,数列中连续相同的最长整数序列算成一段,问数列中共有多少段?

输入格式

  输入的第一行包含一个整数n,表示数列中整数的个数。
  第二行包含n个整数a1, a2, …, an,表示给定的数列,相邻的整数之间用一个空格分隔。

输出格式

  输出一个整数,表示给定的数列有多个段。

样例输入

8
8 8 8 0 12 12 8 0     

样例输出

5

样例说明

  8 8 8是第一段,0是第二段,12 12是第三段,倒数第二个整数8是第四段,最后一个0是第五段。

评测用例规模与约定

  1 ≤ n ≤ 1000,0 ≤ ai ≤ 1000。

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

解题思路:当 当前整数与前一个整数不相等时,分段加1。

#include<iostream>
using namespace std;

int main(){
	int n;
	cin>>n;
	int* nums = new int[n];
	for(int i = 0; i < n; i++){
		cin>>nums[i];
	}
	int count = 1;
	for(int i = 1; i < n; ++i){
		if(nums[i] != nums[i-1]){
			count++;
		}
	}
	cout<<count<<endl;
	return 0;
}

试题编号:201509-2

日期计算

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int y;
	cin>>y;
	int d;
	cin>>d;
	int a[13] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
	int b[13] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366};
	if((y % 4 == 0 && y % 100 != 0) || y % 400 == 0){  
		for(int i = 0; i < 13; i++){
			if(d <= b[i]){
				cout<<i<<endl;
				cout<<d-b[i - 1];
				break;
			}
		}
	}else{
		for(int i = 0; i < 13; i++){
			if(d <= a[i]){
				cout<<i<<endl;
				cout<<d-a[i- 1]; 
				break;
			}
		}
	}
	
	return 0;
}

2015-03

试题编号:201503-1

图像旋转

时间限制:5.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int n, m;
	cin>>n>>m;
	int a[n][m];

	for(int i = 0; i < n; i++)	{
		for(int j = 0; j < m; j++){
			cin>>a[i][j];
		}
	}
	for(int i = m - 1; i >= 0; i--){
		for(int j = 0; j < n; j++){
			cout<<a[j][i]<<" ";
		}
		cout<<endl;
	}
	return 0;
 } 

试题编号:201503-2

数字排序

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

struct cmp{
	bool operator()(const pair<int, int>& a, const pair<int, int>& b){
		if(a.second != b.second)
		{
			return a.second > b.second;  // 按出现次数从大到小排序 

		}else{
				return a.first < b.first;   // 如果出现次数一样,则按值从小到大排序 
		}
	}
};

int main()
{
	int n; 
	cin>>n;
	map<int, int> frequency;  // 整数、次数 
	for(int i = 0; i < n; i++)
	{
		int num;
		cin>>num;
		frequency[num]++;
	}
	vector<pair<int, int> > fre;
	for(map<int, int>::iterator it = frequency.begin(); it != frequency.end(); ++it){
		fre.push_back(make_pair(it->first, it->second));
	} 
	sort(fre.begin(), fre.end(), cmp());
	for(vector<pair<int, int> >::iterator it = fre.begin(); it != fre.end(); ++it){
		cout<<it->first<<" "<<it->second<<endl; 
	}
	return 0;
}

2014-12

试题编号:201412-1

门禁系统

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

int main()
{
	int n;
	cin>>n;
	map<int, int> a;
	for(int i = 0; i < n; i++){
		int num;
		cin>>num;
		a[num]++;
		cout<<a[num]<<" ";
	}
	return 0;
}

试题编号:201412-2

Z字形扫描

时间限制:2.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include<iostream>
using namespace std;

int main()
{
	int n;
	cin>>n;
	int a[n + 1][n + 1];
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			cin>>a[i][j];
		}
	}
	for(int i = 2; i <= 2 * n; i++){
		int start = max(1, i - n), end = min(i - 1, n);  // 范围检查 
		if(i % 2 == 0){  // 偶数行 
			for(int j = end; j >= start; j--){
				cout<<a[j][i - j]<<" ";
			}
		}else{  // 奇数行 
			for(int j = start; j <= end; j++){
				cout<<a[j][i - j]<<" ";
			}
		}
	} 
	return 0;
}

2014-09

试题编号:201409-1

相邻数对

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

int main()
{
	int n;
	cin>>n;
	vector<int> a(n + 1);
	for(int i = 1; i <= n; i++){
		cin>>a[i];
	}
	int count = 0;
	sort(a.begin(), a.end());
	for(int i = 2; i <= n; i++){
		if((a[i] - a[i - 1]) == 1){
			count++;
		}
	}
	cout<<count;
	return 0;
 } 

试题编号:201409-2

画图

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

int paper[101][101];  // 纸张 
int main()
{
	int n;
	cin>>n;
//	vector<vector<int> > paper(101, vector<int>(101, 0));  // 纸张 
	for(int i = 0; i < n; i++){
		int x1, y1, x2, y2;
		cin>>x1>>y1>>x2>>y2;
		for(int i = x1; i < x2; i++){
			for(int j = y1; j < y2; j++){
				paper[i][j] = 1;  // 涂色 
			}
		}
	}
	int sum = 0;
	for(int i = 0; i < 101; i++){
		for(int j = 0; j < 101; j++){
			sum += paper[i][j]; 
		}
	}
	cout<<sum;
	return 0;
}

2014-03

试题编号:201403-1

相反数

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

vector<int> a(1001);
int main()
{
 	int n;
 	cin>>n;
 	for(int i = 0; i < n; i++){
 		int temp;
 		cin>>temp;
 		a[abs(temp)]++;
	}
	
	int count = 0;
	for(int  i = 0; i < 1001; i++){
		if(a[i] == 2){
			count++;
		}
	}
	cout<<count;
	return 0;
}

试题编号:201403-2

窗口

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

#include <iostream>
#include <vector>

using namespace std;

struct Window {
    int x1, y1, x2, y2;
    int order;  // 顺序 
//    bool isActive;  // 是否处于顶层 
};

int main() {
    int N, M;
    cin >> N >> M;

    vector<Window> windows(N);

    for (int i = 0; i < N; ++i) {  // 从底层到顶层
        cin >> windows[i].x1 >> windows[i].y1 >> windows[i].x2 >> windows[i].y2;
        windows[i].order = i + 1;
//        windows[i].isActive = false;
    }

    for (int i = 0; i < M; ++i) {
        int x, y;
        cin >> x >> y;

        int selected_window = -1;
        for (int j = N - 1; j >= 0; --j) {
            if (x >= windows[j].x1 && x <= windows[j].x2 && y >= windows[j].y1 && y <= windows[j].y2) {
                selected_window = j;
                break;
            }
        }

        if (selected_window != -1) {
//        	for(int k = 0; k < N; ++k){
//        		windows[k].isActive = false;
//			}
//			windows[selected_window].isActive = true;
			
            cout << windows[selected_window].order<< endl;
            Window temp = windows[selected_window];  // 改变顺序 
            windows.erase(windows.begin() + selected_window);
            windows.push_back(temp);
        } else {
            cout << "IGNORED" << endl;
        }
    }

    return 0;
}

2013-12

试题编号:201312-1

出现次数最多的数

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

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

int main()
{
	int n;
	cin>>n;
	map<int, int> fre;
	for(int i= 0; i < n; i++){
		int num;
		cin>>num;
		fre[num]++;
	}
	int maxFre = 0;  // 出现次数
	int result = 10001;  
	for(map<int, int>::iterator it = fre.begin(); it != fre.end(); ++it){
		if(it->second > maxFre){  // 找出出现次数最多的那个 
			maxFre = it->second; 
			result = it->first;
		}else if(it->second == maxFre && it->first < result){  // 出现次数同样多,输出小的那个 
			result = it->first;
		}
	}
	cout<<result;
	return 0;
 } 

试题编号:201312-2

ISBN号码

时间限制:1.0s

内存限制:256.0MB

编译环境:Dev-CPP(C++语言C++11标准)

// 80分
#include<iostream>
#include<string>
using namespace std;

int main(){
	string str;
	cin >> str;
	int sum = 0;
	int count = 1;
	for(int i = 0; i < 12; i++){
		if(i != 1 && i != 5 && i != 11){
			sum += (str[i] - '0') * count;
			count++;
		}
	} 
	char q = str[12];
	sum = sum % 11;
	if(sum == 10){
		if('X' != q){
			str[12] = 'X';
			cout << str;
		}else{
			cout<<"Right";
		}
	} else if(sum != (q - '0')){
		str[12] = '0' + sum;
		cout << str;
	} else {
		cout << "Right";
	}
	return 0;
}

2020 CCF CSP-J2

第一题:优秀的拆分

问题描述
一般来说,一个正整数可以拆分成若干个正整数的和。例如,1=1,10=1+2+3+4等。对于正整数n的一种特定拆分,我们称它为“优秀的",当且仅当在这种拆分下,n被分解为了若干个不同的2的正整数次幂。注意,一个数x能被表示成2的正整数次幂,当且仅当x能通过正整数个2相乘在一起得到。例如,10=8+2=2^3+2^1是一个优秀的拆分。但是,7=4+2+1=2+2^1+2^0就不是一个优秀的拆分,因为1不是2的正整数次幂。现在,给定正整数n,你需要判断这个数的所有拆分中,是否存在优秀的拆分。若存在,请你给出具体的拆分方案。

输入格式
输入文件只有一行,一个正整数n,代表需要判断的数。

输出格式

如果这个数的所有拆分中,存在优秀的拆分。那么,你需要从大到小输出这个拆分中的每一个数,相邻两个数之间用一个空格隔开。可以证明,在规定了拆分数字的顺序后,该拆分方案是唯一的。若不存在优秀的拆分,输出"-1"(不包含双引号)。

输入输出样例

in:6
out:4 2

in:7
out:-1

数据范围与提示

对于20%的数据,n<=10 对于另外20%的数据,保证n为奇数。 对于另外20%的数据,保证n为2的正整数次幂。 对于80%的数据,n<=1024 对于100%的数据,1<=n<=1x10^7

解题思路:此题是判断一个十进制正整数能否分解为若干个不同的2的正整数次幂和的问题,本质上就是一个进制转换问题。 因为一个十进制正整数必有唯一对应的二进制数,而一个二进制数转换为对应的十进制数时,可表示为若干个不同的2的正整数次幂和再加上 x*2^0(其中的 x 依据不同的十进制正整数取0或取1)。显然,此题中 x 不能取1,因为若取1,则2的0次幂将被采用,显然不符合题目给出的正整数次幂的要求。据此,在算法设计时可对给定的正整数 n 进行 & 位运算 n&1,若n&1为真,则上文 x*2^0中的x取1,即正整数n的二进制表示中的最低位取1,也即2的0次幂将被采用,显然不符题意。故若n&1==1,则依据题意输出 -1。 之后,对给定的正整数 n 进行右移位运算,若n>>i&1为真(其中的i为右移的位数),表示第i为是1,它对应输出2^i,即1<<i。由于题目给的数据范围最大为1x10^7,对应的二进制数为100110001001011010000000(总共24位,最高位贡献为1*2^23),写成2的次幂形式为 2^23+2^20+2^19+2^15+2^12+2^10+2^9+2^7

#include <bits/stdc++.h>
using namespace std;
 
int main() {
	int n;
	cin>>n;
	if(n & 1)
		cout<<"-1";
	else {
		for(int i=23; i>=1; i--) {
			if(n>>i & 1)
				cout<<(1<<i)<<" ";
		}
	}
	return 0;
}

相似题

#include<iostream>
using namespace std;

void fun(int n){
	if(n == 0){
		cout<<"0";
		return;
	}
	else if(n == 1){
		cout<<"2(0)";
		return;
	}
	else if(n == 2){
		cout<<"2(1)";
		return;
	}
	else{
		int t = 0;
		while((1 << t) <= n)	t++;
		t -= 1;  // 回退1 
		if(t != 1){
			cout<<"2(";
			fun(t);
			cout<<")";
		}else	cout<<"2";
		int res = n - (1<<t);
		if(res != 0){
			cout<<"+";
			fun(res);
		}
	}
}

int main()
{
	int n;
	cin>>n;
	fun(n);
	return 0;
 } 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值