目录
折点计数
试题编号: | 201604-1 |
试题名称: | 折点计数 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 给定n个整数表示一个商店连续n天的销售量。如果某天之前销售量在增长,而后一天销售量减少,则称这一天为折点,反过来如果之前销售量减少而后一天销售量增长,也称这一天为折点。其他的天都不是折点。如下图中,第3天和第6天是折点。 给定n个整数a1, a2, …, an表示销售量,请计算出这些天总共有多少个折点。 输入格式 输入的第一行包含一个整数n。 第二行包含n个整数,用空格分隔,分别表示a1, a2, …, an。 输出格式 输出一个整数,表示折点出现的数量。 样例输入 7 5 4 1 2 3 6 4 样例输出 2 评测用例规模与约定 所有评测用例满足:1 ≤ n ≤ 1000,每天的销售量是不超过10000的非负整数。 |
代码:
#include <stdio.h>
#define N 1000
int a[N];
int main(void)
{
int n, i, count;
// 读入数据
scanf("%d", &n);
for(i=0; i<n; i++)
scanf("%d", &a[i]);
// 计算折点
count = 0;
for(i=1; i<n-1; i++)
if((a[i-1] < a[i] && a[i] > a[i+1]) || (a[i-1] > a[i] && a[i] < a[i+1]))
count++;
// 输出结果
printf("%d\n", count);
return 0;
}
俄罗斯方块
试题编号: | 201604-2 |
试题名称: | 俄罗斯方块 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游戏。 游戏在一个15行10列的方格图上进行,方格图上的每一个格子可能已经放置了方块,或者没有放置方块。每一轮,都会有一个新的由4个小方块组成的板块从方格图的上方落下,玩家可以操作板块左右移动放到合适的位置,当板块中某一个方块的下边缘与方格图上的方块上边缘重合或者达到下边界时,板块不再移动,如果此时方格图的某一行全放满了方块,则该行被消除并得分。 在这个问题中,你需要写一个程序来模拟板块下落,你不需要处理玩家的操作,也不需要处理消行和得分。 具体的,给定一个初始的方格图,以及一个板块的形状和它下落的初始位置,你要给出最终的方格图。 输入格式 输入的前15行包含初始的方格图,每行包含10个数字,相邻的数字用空格分隔。如果一个数字是0,表示对应的方格中没有方块,如果数字是1,则表示初始的时候有方块。输入保证前4行中的数字都是0。 输入的第16至第19行包含新加入的板块的形状,每行包含4个数字,组成了板块图案,同样0表示没方块,1表示有方块。输入保证板块的图案中正好包含4个方块,且4个方块是连在一起的(准确的说,4个方块是四连通的,即给定的板块是俄罗斯方块的标准板块)。 第20行包含一个1到7之间的整数,表示板块图案最左边开始的时候是在方格图的哪一列中。注意,这里的板块图案指的是16至19行所输入的板块图案,如果板块图案的最左边一列全是0,则它的左边和实际所表示的板块的左边是不一致的(见样例) 输出格式 输出15行,每行10个数字,相邻的数字之间用一个空格分隔,表示板块下落后的方格图。注意,你不需要处理最终的消行。 样例输入 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 3 样例输出 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 |
解决代码:
#include <iostream>
const int ROW = 15;
const int COL = 10;
const int N = 4;
int board[ROW+1][COL];
int block[N][N];
struct {
int row, col;
} coords[N];
using namespace std;
int main()
{
int row, col;
// 输入数据
for(int i=0; i<ROW; i++)
for(int j=0; j<COL; j++)
cin >> board[i][j];
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
cin >> block[i][j];
cin >> col;
// 底边全放1
for(int j=0; j<COL; j++)
board[ROW][j] = 1;
// 提取小方块坐标
int k = 0;
for(int i=N-1; i>=0; i--)
for(int j=0; j<N; j++)
if(block[i][j] == 1) {
coords[k].row = i;
coords[k].col = j;
k++;
}
// 模拟小方块落下过程
row = 1;
col--;
bool checkflag;
for(;;) {
checkflag = false;
for(int i=0; i<N; i++)
if(board[row + coords[i].row][col + coords[i].col] == 1) {
checkflag = true;
break;
}
if(checkflag)
break;
row++;
}
row--;
// 合并小方块到方格
for(int i=0; i<N; i++)
board[row + coords[i].row][col + coords[i].col] = 1;
// 输出结果
for(int i=0; i<ROW; i++) {
for(int j=0; j<COL; j++) {
if(j != 0)
cout << " ";
cout << board[i][j];
}
cout << endl;
}
return 0;
}
最大波动
试题编号: | 201609-1 |
试题名称: | 最大波动 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 小明正在利用股票的波动程度来研究股票。小明拿到了一只股票每天收盘时的价格,他想知道,这只股票连续几天的最大波动值是多少,即在这几天中某天收盘价格与前一天收盘价格之差的绝对值最大是多少。 输入格式 输入的第一行包含了一个整数n,表示小明拿到的收盘价格的连续天数。 第二行包含n个正整数,依次表示每天的收盘价格。 输出格式 输出一个整数,表示这只股票这n天中的最大波动值。 样例输入 6 2 5 5 7 3 5 样例输出 4 样例说明 第四天和第五天之间的波动最大,波动值为|3-7|=4。 评测用例规模与约定 对于所有评测用例,2 ≤ n ≤ 1000。股票每一天的价格为1到10000之间的整数。 |
解决代码:
#include <stdio.h>
#define MAX(x, y) ((x > y) ? (x) : (y))
int main(void)
{
int n, first, second, delta, maxval=0;
// 输入n,输第1个数(从逻辑上来说应该写两句,为了简洁只需要写一句)
scanf("%d%d", &n, &first);
while(--n) {
// 输入第2至第n个数
scanf("%d", &second);
// 求差值(波动值),取绝对值,求最大值
delta = second - first;
if(delta<0)
delta = -delta;
maxval = MAX(maxval, delta);
first = second;
}
// 输出结果
printf("%d\n", maxval);
return 0;
}
火车购票
试题编号: | 201609-2 |
试题名称: | 火车购票 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 请实现一个铁路购票系统的简单座位分配算法,来处理一节车厢的座位分配。 假设一节车厢有20排、每一排5个座位。为方便起见,我们用1到100来给所有的座位编号,第一排是1到5号,第二排是6到10号,依次类推,第20排是96到100号。 购票时,一个人可能购一张或多张票,最多不超过5张。如果这几张票可以安排在同一排编号相邻的座位,则应该安排在编号最小的相邻座位。否则应该安排在编号最小的几个空座位中(不考虑是否相邻)。 假设初始时车票全部未被购买,现在给了一些购票指令,请你处理这些指令。 输入格式 输入的第一行包含一个整数n,表示购票指令的数量。 第二行包含n个整数,每个整数p在1到5之间,表示要购入的票数,相邻的两个数之间使用一个空格分隔。 输出格式 输出n行,每行对应一条指令的处理结果。 对于购票指令p,输出p张车票的编号,按从小到大排序。 样例输入 4 2 5 4 2 样例输出 1 2 6 7 8 9 10 11 12 13 14 3 4 样例说明 1) 购2张票,得到座位1、2。 2) 购5张票,得到座位6至10。 3) 购4张票,得到座位11至14。 4) 购2张票,得到座位3、4。 评测用例规模与约定 对于所有评测用例,1 ≤ n ≤ 100,所有购票数量之和不超过100。 |
解决代码:
#include <iostream>
#include <map>
using namespace std;
const int N = 20;
const int NUM = 5;
int main()
{
map<int,int> m;
int n, v, start, end;
// 初始化车厢票源
for(int i=1; i<=N; i++)
m[i] = NUM;
// 输入数据,分配车票,输出结果
cin >> n;
for(int i=1; i<=n; i++) {
// 输入数据:购买火车票张数
cin >> v;
// 分配车票(同一排分配)并且输出结果
for(map<int,int>::iterator it=m.begin(); it!=m.end(); it++) {
if(it->second >= v) {
// 输出结果
start = (it->first - 1) * NUM + 1 + (NUM - it->second);
end = start + v - 1;
for(int j=start; j<=end; j++) {
if(j != start)
cout << " ";
cout << j;
}
cout << endl;
// 对于票数已经分配完毕的排,删除
if(it->second == v)
m.erase(it);
else
it->second = it->second - v;
v = 0;
break;
}
}
// 分配车票(多排分配)并且输出结果
bool nofirstflag = false;
while(v > 0) {
for(map<int,int>::iterator it=m.begin(); it!=m.end(); it++) {
if(it->second >= v) {
// 输出结果
start = (it->first - 1) * NUM + 1 + (NUM - it->second);
end = start + v - 1;
for(int j=start; j<=end; j++) {
if(nofirstflag)
cout << " ";
cout << j;
nofirstflag = true;
}
// 对于票数已经分配完毕的排,删除
if(it->second == v)
m.erase(it);
else
it->second = it->second - v;
v = 0;
break;
} else {
// 输出结果
start = (it->first - 1) * NUM + 1 + (NUM - it->second);
end = start + it->second - 1;
for(int j=start; j<=end; j++) {
if(nofirstflag)
cout << " ";
cout << j;
nofirstflag = true;
}
v = v - it->second;
// 对于票数已经分配完毕的排,删除
m.erase(it);
}
}
cout << endl;
}
}
return 0;
}
中间数
试题编号: | 201612-1 |
试题名称: | 中间数 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 在一个整数序列a1, a2, …, an中,如果存在某个数,大于它的整数数量等于小于它的整数数量,则称其为中间数。在一个序列中,可能存在多个下标不相同的中间数,这些中间数的值是相同的。 给定一个整数序列,请找出这个整数序列的中间数的值。 输入格式 输入的第一行包含了一个整数n,表示整数序列中数的个数。 第二行包含n个正整数,依次表示a1, a2, …, an。 输出格式 如果约定序列的中间数存在,则输出中间数的值,否则输出-1表示不存在中间数。 样例输入 6 2 6 5 6 3 5 样例输出 5 样例说明 比5小的数有2个,比5大的数也有2个。 样例输入 4 3 4 6 7 样例输出 -1 样例说明 在序列中的4个数都不满足中间数的定义。 样例输入 5 3 4 6 6 7 样例输出 -1 样例说明 在序列中的5个数都不满足中间数的定义。 评测用例规模与约定 对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ ai ≤ 1000。 |
解决代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1000;
int val[N];
int main()
{
int n, mid, leftcount, rightcount;
// 输入数据
cin >> n;
for(int i=0; i<n; i++)
cin >> val[i];
// 排序
sort(val, val+n);
// 找出中间数
mid = n / 2;
leftcount = mid;
rightcount = n - mid - 1;
// 去掉左边与中间相同值数的个数
for(int i=mid-1; i>=0; i--)
if(val[i] == val[mid])
leftcount--;
else
break;
// 去掉右边与中间相同值数的个数
for(int i=mid+1; i<n; i++)
if(val[i] == val[mid])
rightcount--;
else
break;
// 输出结果
if(leftcount == rightcount)
cout << val[mid] << endl;
else
cout << -1 << endl;
return 0;
}
工资计算
试题编号: | 201612-2 |
试题名称: | 工资计算 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 小明的公司每个月给小明发工资,而小明拿到的工资为交完个人所得税之后的工资。假设他一个月的税前工资(扣除五险一金后、未扣税前的工资)为S元,则他应交的个人所得税按如下公式计算: 1) 个人所得税起征点为3500元,若S不超过3500,则不交税,3500元以上的部分才计算个人所得税,令A=S-3500元; 2) A中不超过1500元的部分,税率3%; 3) A中超过1500元未超过4500元的部分,税率10%; 4) A中超过4500元未超过9000元的部分,税率20%; 5) A中超过9000元未超过35000元的部分,税率25%; 6) A中超过35000元未超过55000元的部分,税率30%; 7) A中超过55000元未超过80000元的部分,税率35%; 8) A中超过80000元的部分,税率45%; 例如,如果小明的税前工资为10000元,则A=10000-3500=6500元,其中不超过1500元部分应缴税1500×3%=45元,超过1500元不超过4500元部分应缴税(4500-1500)×10%=300元,超过4500元部分应缴税(6500-4500)×20%=400元。总共缴税745元,税后所得为9255元。 已知小明这个月税后所得为T元,请问他的税前工资S是多少元。 输入格式 输入的第一行包含一个整数T,表示小明的税后所得。所有评测数据保证小明的税前工资为一个整百的数。 输出格式 输出一个整数S,表示小明的税前工资。 样例输入 9255 样例输出 10000 评测用例规模与约定 对于所有评测用例,1 ≤ T ≤ 100000。 |
解决代码:
/* CCF201612-2 工资计算 */
#include <iostream>
using namespace std;
//#define DEBUG
int salaryrange[] = {3500, 3500+1500, 3500+4500, 3500+9000, 3500+35000, 3500+55000, 3500+80000 };
int taxrate[] = {3, 10, 20, 25, 30, 35, 45};
const int SIZE = sizeof(salaryrange) / sizeof(int);
int range[SIZE];
int main()
{
int t, s;
// 计算各种收入范围
range[0] = salaryrange[0];
for(int i=1; i<SIZE; i++) {
range[i] = range[i-1] + (salaryrange[i] - salaryrange[i-1])
- (salaryrange[i] - salaryrange[i-1]) * taxrate[i-1] / 100;
}
#ifdef DEBUG
for(int i=0; i<SIZE; i++)
cout << range[i] << " ";
cout << endl;
#endif
// 输入数据:
cin >> t;
// 计算收入范围
int i;
for(i=0; i<SIZE; i++)
if(t <= range[i])
break;
// 计算税前工资
if(i == 0)
s = t;
else {
s = salaryrange[i-1] + (t - range[i-1]) * 100 / (100 - taxrate[i-1]);
}
// 输出结果
cout << s << endl;
return 0;
}
分蛋糕
试题编号: | 201703-1 |
试题名称: | 分蛋糕 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 小明今天生日,他有n块蛋糕要分给朋友们吃,这n块蛋糕(编号为1到n)的重量分别为a1, a2, …, an。小明想分给每个朋友至少重量为k的蛋糕。小明的朋友们已经排好队准备领蛋糕,对于每个朋友,小明总是先将自己手中编号最小的蛋糕分给他,当这个朋友所分得蛋糕的重量不到k时,再继续将剩下的蛋糕中编号最小的给他,直到小明的蛋糕分完或者这个朋友分到的蛋糕的总重量大于等于k。 请问当小明的蛋糕分完时,总共有多少个朋友分到了蛋糕。 输入格式 输入的第一行包含了两个整数n, k,意义如上所述。 第二行包含n个正整数,依次表示a1, a2, …, an。 输出格式 输出一个整数,表示有多少个朋友分到了蛋糕。 样例输入 6 9 2 6 5 6 3 5 样例输出 3 样例说明 第一个朋友分到了前3块蛋糕,第二个朋友分到了第4、5块蛋糕,第三个朋友分到了最后一块蛋糕。 评测用例规模与约定 对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ k ≤ 10000,1 ≤ ai ≤ 1000。 |
解决代码:
/* CCF201703-1 分蛋糕 */
#include <stdio.h>
int main(void)
{
int n, k, count=0, val, sub=0;
scanf("%d%d", &n, &k);
while(n--) {
scanf("%d", &val);
if((sub += val) >= k) {
count++;
sub = 0;
}
}
if(sub > 0)
count++;
printf("%d\n", count);
return 0;
}
学生排队
试题编号: | 201703-2 |
试题名称: | 学生排队 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 体育老师小明要将自己班上的学生按顺序排队。他首先让学生按学号从小到大的顺序排成一排,学号小的排在前面,然后进行多次调整。一次调整小明可能让一位同学出队,向前或者向后移动一段距离后再插入队列。 例如,下面给出了一组移动的例子,例子中学生的人数为8人。 0)初始队列中学生的学号依次为1, 2, 3, 4, 5, 6, 7, 8; 1)第一次调整,命令为“3号同学向后移动2”,表示3号同学出队,向后移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 3, 6, 7, 8; 2)第二次调整,命令为“8号同学向前移动3”,表示8号同学出队,向前移动3名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 5, 8, 3, 6, 7; 3)第三次调整,命令为“3号同学向前移动2”,表示3号同学出队,向前移动2名同学的距离,再插入到队列中,新队列中学生的学号依次为1, 2, 4, 3, 5, 8, 6, 7。 小明记录了所有调整的过程,请问,最终从前向后所有学生的学号依次是多少? 请特别注意,上述移动过程中所涉及的号码指的是学号,而不是在队伍中的位置。在向后移动时,移动的距离不超过对应同学后面的人数,如果向后移动的距离正好等于对应同学后面的人数则该同学会移动到队列的最后面。在向前移动时,移动的距离不超过对应同学前面的人数,如果向前移动的距离正好等于对应同学前面的人数则该同学会移动到队列的最前面。 输入格式 输入的第一行包含一个整数n,表示学生的数量,学生的学号由1到n编号。 第二行包含一个整数m,表示调整的次数。 接下来m行,每行两个整数p, q,如果q为正,表示学号为p的同学向后移动q,如果q为负,表示学号为p的同学向前移动-q。 输出格式 输出一行,包含n个整数,相邻两个整数之间由一个空格分隔,表示最终从前向后所有学生的学号。 样例输入 8 3 3 2 8 -3 3 -2 样例输出 1 2 4 3 5 8 6 7 评测用例规模与约定 对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 1000,所有移动均合法。 |
解决代码:
/* CCF201703-2 学生排队 */
#include <iostream>
#include <vector>
using namespace std;
vector<int> v;
int find(int x)
{
int ret = - 1;
for(int i = 0; i < (int)v.size(); i++)
if(v[i] == x)
return i;
return ret;
}
int main()
{
int n, m, p, q;
// 读入数据
cin >> n >> m;
// 初始化
for(int i=1; i<=n; i++)
v.push_back(i);
// 模拟移动过程
for(int i=1; i<=m; i++) {
cin >> p >> q;
int pos = find(p);
v.insert(v.begin() + pos + (q > 0 ? q + 1 : q), p);
v.erase(v.begin() + pos + (q < 0 ? 1 : 0));
}
// 输出结果
cout << v[0];
for(int i = 1; i < (int)v.size(); i++)
cout << " " << v[i];
cout << endl;
return 0;
}
打酱油
试题编号: | 201709-1 |
试题名称: | 打酱油 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 小明带着N元钱去买酱油。酱油10块钱一瓶,商家进行促销,每买3瓶送1瓶,或者每买5瓶送2瓶。请问小明最多可以得到多少瓶酱油。 输入格式 输入的第一行包含一个整数N,表示小明可用于买酱油的钱数。N是10的整数倍,N不超过300。 输出格式 输出一个整数,表示小明最多可以得到多少瓶酱油。 样例输入 40 样例输出 5 样例说明 把40元分成30元和10元,分别买3瓶和1瓶,其中3瓶送1瓶,共得到5瓶。 样例输入 80 样例输出 11 样例说明 把80元分成30元和50元,分别买3瓶和5瓶,其中3瓶送1瓶,5瓶送2瓶,共得到11瓶。 |
解决代码;
/* CCF201709-1 打酱油 */
#include <stdio.h>
const int ONE = 1;
const int TWO = 2;
const int FIVE = 5;
const int THREE = 3;
const int PRICE = 10;
int main(void)
{
int n, group1, group2, group3;
scanf("%d", &n);
group1 = n / PRICE / FIVE;
group2 = (n - group1 * PRICE * FIVE) / PRICE / THREE;
group3 = (n - group1 * PRICE * FIVE - group2 * PRICE * THREE) / PRICE;
printf("%d\n", group1 * (FIVE + TWO) + group2 * (THREE + ONE) + group3);
return 0;
}
公共钥匙盒
试题编号: | 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 ≤ w ≤ N, 1 ≤ s, c ≤ 30; 对于60%的评测用例,1 ≤ N, K ≤ 50,1 ≤ w ≤ N,1 ≤ s ≤ 300,1 ≤ c ≤ 50; 对于所有评测用例,1 ≤ N, K ≤ 1000,1 ≤ w ≤ N,1 ≤ s ≤ 10000,1 ≤ c ≤ 100。 |
解决代码;
/* CCF201709-2 公共钥匙盒 */
#include <iostream>
#include <queue>
#include <stdio.h>
//#define DEBUG
using namespace std;
struct _node {
int num; // 钥匙号
char op; // 操作:'G'-取钥匙,'R'-还钥匙
int time; // 时间点
bool operator <(_node a)const
{
if(time != a.time)
return time > a.time;
else if(op != a.op)
return op < a.op;
else
return num > a.num;
}
};
const int N = 1000;
int hook[N+1];
int main()
{
int n, k;
int w, s, c;
priority_queue<_node> q;
_node t;
scanf("%d%d", &n, &k);
for(int i=1; i<=n; i++)
hook[i] = i;
#ifdef DEBUG
printf("status: ");
for(int i=1; i<=n; i++)
printf("%d", hook[i]);
printf("\n");
#endif
for(int i=1; i<=k; i++) {
scanf("%d%d%d", &w, &s, &c);
t.num = w;
t.time = s;
t.op = 'G';
q.push(t);
t.op = 'R';
t.time = s + c;
q.push(t);
}
while(!q.empty()) {
t = q.top();
q.pop();
if(t.op == 'G') {
for(int i=1; i<=n; i++) {
if(hook[i] == t.num) {
hook[i] = 0;
break;
}
}
} else { // t.op == 'R'
for(int i=1; i<=n; i++) {
if(hook[i] == 0) {
hook[i] = t.num;
break;
}
}
}
#ifdef DEBUG
printf("status: ");
for(int i=1; i<=n; i++)
printf("%d", hook[i]);
printf("\n");
#endif
}
for(int i=1; i<=n; i++) {
if(i != 1)
printf(" ");
printf("%d", hook[i]);
}
printf("\n");
return 0;
}
跳一跳
试题编号: | 201803-1 |
试题名称: | 跳一跳 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 近来,跳一跳这款小游戏风靡全国,受到不少玩家的喜爱。 简化后的跳一跳规则如下:玩家每次从当前方块跳到下一个方块,如果没有跳到下一个方块上则游戏结束。 如果跳到了方块上,但没有跳到方块的中心则获得1分;跳到方块中心时,若上一次的得分为1分或这是本局游戏的第一次跳跃则此次得分为2分,否则此次得分比上一次得分多两分(即连续跳到方块中心时,总得分将+2,+4,+6,+8...)。 现在给出一个人跳一跳的全过程,请你求出他本局游戏的得分(按照题目描述的规则)。 输入格式 输入包含多个数字,用空格分隔,每个数字都是1,2,0之一,1表示此次跳跃跳到了方块上但是没有跳到中心,2表示此次跳跃跳到了方块上并且跳到了方块中心,0表示此次跳跃没有跳到方块上(此时游戏结束)。 输出格式 输出一个整数,为本局游戏的得分(在本题的规则下)。 样例输入 1 1 2 2 2 1 1 2 2 0 样例输出 22 数据规模和约定 对于所有评测用例,输入的数字不超过30个,保证0正好出现一次且为最后一个数字。 |
解决代码:
/* CCF201803-1 跳一跳 */
#include <iostream>
using namespace std;
int main()
{
int a, sum = 0, plus = 0;
while(scanf("%d", &a) != EOF && a) {
sum += a;
if(a == 1)
plus = 0;
else if(a == 2) {
sum += plus;
plus += 2;
}
}
printf("%d\n", sum);
return 0;
}
碰撞的小球
试题编号: | 201803-2 |
试题名称: | 碰撞的小球 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 数轴上有一条长度为L(L为偶数)的线段,左端点在原点,右端点在坐标L处。有n个不计体积的小球在线段上,开始时所有的小球都处在偶数坐标上,速度方向向右,速度大小为1单位长度每秒。 当小球到达线段的端点(左端点或右端点)的时候,会立即向相反的方向移动,速度大小仍然为原来大小。 当两个小球撞到一起的时候,两个小球会分别向与自己原来移动的方向相反的方向,以原来的速度大小继续移动。 现在,告诉你线段的长度L,小球数量n,以及n个小球的初始位置,请你计算t秒之后,各个小球的位置。 提示 因为所有小球的初始位置都为偶数,而且线段的长度为偶数,可以证明,不会有三个小球同时相撞,小球到达线段端点以及小球之间的碰撞时刻均为整数。 同时也可以证明两个小球发生碰撞的位置一定是整数(但不一定是偶数)。 输入格式 输入的第一行包含三个整数n, L, t,用空格分隔,分别表示小球的个数、线段长度和你需要计算t秒之后小球的位置。 第二行包含n个整数a1, a2, …, an,用空格分隔,表示初始时刻n个小球的位置。 输出格式 输出一行包含n个整数,用空格分隔,第i个整数代表初始时刻位于ai的小球,在t秒之后的位置。 样例输入 3 10 5 4 6 8 样例输出 7 9 9 样例说明 初始时,三个小球的位置分别为4, 6, 8 一秒后,三个小球的位置分别为5, 7, 9。 两秒后,第三个小球碰到墙壁,速度反向,三个小球位置分别为6, 8, 10。 三秒后,第二个小球与第三个小球在位置9发生碰撞,速度反向(注意碰撞位置不一定为偶数),三个小球位置分别为7, 9, 9。 四秒后,第一个小球与第二个小球在位置8发生碰撞,速度反向,第三个小球碰到墙壁,速度反向,三个小球位置分别为8, 8, 10。 五秒后,三个小球的位置分别为7, 9, 9。 样例输入 10 22 30 14 12 16 6 10 2 8 20 18 4 样例输出 6 6 8 2 4 0 4 12 10 2 数据规模和约定 对于所有评测用例,1 ≤ n ≤ 100,1 ≤ t ≤ 100,2 ≤ L ≤ 1000,0 < ai < L。L为偶数。 保证所有小球的初始位置互不相同且均为偶数。 |
解决代码;
/* CCF201803-2 碰撞的小球 */
#include <iostream>
using namespace std;
const int L = 1000;
int pos[L + 1], step[L + 1];
int main()
{
int n, l, t;
cin >> n >> l >> t;
for(int i = 0; i < n; i++) {
cin >> pos[i];
// 开始往右走,到达两端则回头
step[i] = 1;
if(pos[i] == l || pos[i] == 0)
step[i] = -step[i];
}
for(int i = 0; i < t; i++) {
// 走一步
for(int j = 0; j < n; j++) {
pos[j] += step[j];
// 到达两端则回头
if(pos[j] == l || pos[j] == 0)
step[j] = -step[j];
}
// 判断是否碰头,碰头则掉头(要避免重复比较)
for(int j = 0; j < n; j++)
for(int k = j + 1; k < n; k++)
if(pos[k] == pos[j])
step[k] = -step[k], step[j] = -step[j];
}
for(int i = 0; i < n; i++)
cout << pos[i] << " ";
cout << endl;
return 0;
}
卖菜
试题编号: | 201809-1 |
试题名称: | 卖菜 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 在一条街上有n个卖菜的商店,按1至n的顺序排成一排,这些商店都卖一种蔬菜。第一天,每个商店都自己定了一个价格。店主们希望自己的菜价和其他商店的一致,第二天,每一家商店都会根据他自己和相邻商店的价格调整自己的价格。具体的,每家商店都会将第二天的菜价设置为自己和相邻商店第一天菜价的平均值(用去尾法取整)。注意,编号为1的商店只有一个相邻的商店2,编号为n的商店只有一个相邻的商店n-1,其他编号为i的商店有两个相邻的商店i-1和i+1。给定第一天各个商店的菜价,请计算第二天每个商店的菜价。 输入格式 输入的第一行包含一个整数n,表示商店的数量。第二行包含n个整数,依次表示每个商店第一天的菜价。 输出格式 输出一行,包含n个正整数,依次表示每个商店第二天的菜价。 样例输入 8 4 1 3 1 6 5 17 9 样例输出 2 2 1 3 4 9 10 13 数据规模和约定 对于所有评测用例,2 ≤ n ≤ 1000,第一天每个商店的菜价为不超过10000的正整数。 |
解决代码;
#include<stdio.h>
#define MAXN 1005
int arr[MAXN];
int ans[MAXN];
int n;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&arr[i]);
}
for(int i=0;i<n;i++){
if(i==0){
if(n>1) ans[i]=(arr[i]+arr[i+1])/2;
}
else if(i==n-1){
if(n>1) ans[i]=(arr[i]+arr[i-1])/2;
}
else ans[i]=(arr[i-1]+arr[i]+arr[i+1])/3;
printf("%d ",ans[i]);
}
return 0;
}
买菜
试题编号: | 201809-2 |
试题名称: | 买菜 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 小H和小W来到了一条街上,两人分开买菜,他们买菜的过程可以描述为,去店里买一些菜然后去旁边的一个广场把菜装上车,两人都要买n种菜,所以也都要装n次车。具体的,对于小H来说有n个不相交的时间段[a1,b1],[a2,b2]…[an,bn]在装车,对于小W来说有n个不相交的时间段[c1,d1],[c2,d2]…[cn,dn]在装车。其中,一个时间段[s, t]表示的是从时刻s到时刻t这段时间,时长为t-s。 由于他们是好朋友,他们都在广场上装车的时候会聊天,他们想知道他们可以聊多长时间。 输入格式 输入的第一行包含一个正整数n,表示时间段的数量。接下来n行每行两个数ai,bi,描述小H的各个装车的时间段。接下来n行每行两个数ci,di,描述小W的各个装车的时间段。 输出格式 输出一行,一个正整数,表示两人可以聊多长时间。 样例输入 4 1 3 5 6 9 13 14 15 2 4 5 7 10 11 13 14 样例输出 3 据规模和约定 对于所有的评测用例,1 ≤ n ≤ 2000, ai < bi < ai+1,ci < di < ci+1,对于所有的i(1 ≤ i ≤ n)有,1 ≤ ai, bi, ci, di ≤ 1000000。。 |
解决代码;
#include<stdio.h>
#define MAXN 2005
struct DURATION{
int s,t;
}dura1[MAXN],dura2[MAXN];
int n;
int ans;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d",&dura1[i].s,&dura1[i].t);
}
for(int i=0;i<n;i++){
scanf("%d%d",&dura2[i].s,&dura2[i].t);
}
int i=0,j=0;
int ans=0;
while(i<n && j<n){
if(dura1[i].t<=dura2[j].s){
i++;
continue;
}
if(dura1[i].s<dura2[j].s && dura1[i].t<dura2[j].t){
ans+=dura1[i].t-dura2[j].s;
i++;
continue;
}
if(dura1[i].s>=dura2[j].s && dura1[i].t<dura2[j].t){
ans+=dura1[i].t-dura1[i].s;
i++;
continue;
}
if(dura1[i].s>=dura2[j].s && dura1[i].s<=dura2[j].t && dura1[i].t>=dura2[j].t){
ans+=dura2[j].t-dura1[i].s;
j++;
continue;
}
if(dura1[i].s>dura2[j].t){
j++;
continue;
}
if(dura1[i].s<=dura2[j].t && dura1[i].t>=dura2[j].t){
ans+=dura2[j].t-dura2[j].s;
j++;
continue;
}
}
printf("%d",ans);
return 0;
}
小明上学
试题编号: | 201812-1 |
试题名称: | 小明上学 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 小明是汉东省政法大学附属中学的一名学生,他每天都要骑自行车往返于家和学校。为了能尽可能充足地睡眠,他希望能够预计自己上学所需要的时间。他上学需要经过数段道路,相邻两段道路之间设有至多一盏红绿灯。 京州市的红绿灯是这样工作的:每盏红绿灯有红、黄、绿三盏灯和一个能够显示倒计时的显示牌。假设红绿灯被设定为红灯 r 秒,黄灯 y 秒,绿灯 g 秒,那么从 0 时刻起,[0,r) 秒内亮红灯,车辆不许通过;[r, r+g) 秒内亮绿灯,车辆允许通过;[r+g, r+g+y) 秒内亮黄灯,车辆不许通过,然后依次循环。倒计时的显示牌上显示的数字 l(l > 0)是指距离下一次信号灯变化的秒数。 一次上学的路上,小明记录下了经过每段路的时间,和各个红绿灯在小明到达路口时的颜色和倒计时秒数。希望你帮忙计算此次小明上学所用的时间。 输入格式 输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 1e6。 输入的第二行包含一个正整数 n(n ≤ 100),表示小明总共经过的道路段数和看到的红绿灯数目。 接下来的 n 行,每行包含空格分隔的两个整数 k、t。k=0 表示经过了一段道路,耗时 t 秒,此处 t 不超过 1e6;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 秒。 |
解决代码;
#include<stdio.h>
#include<string.h>
#define MAXN 105
using namespace std;
int main(){
int r,y,g;
int n;
int k,t;
int ans=0;
scanf("%d%d%d",&r,&y,&g);
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d",&k,&t);
if(k==0) ans+=t;
else if(k==1){
ans+=t;
}
else if(k==2){
ans+=t;
ans+=r;
}
}
printf("%d\n",ans);
return 0;
}
小明放学
试题编号: | 201812-2 |
试题名称: | 小明放学 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 汉东省政法大学附属中学所在的光明区最近实施了名为“智慧光明”的智慧城市项目。具体到交通领域,通过“智慧光明”终端,可以看到光明区所有红绿灯此时此刻的状态。小明的学校也安装了“智慧光明”终端,小明想利用这个终端给出的信息,估算自己放学回到家的时间。 一次放学的时候,小明已经规划好了自己回家的路线,并且能够预测经过各个路段的时间。同时,小明通过学校里安装的“智慧光明”终端,看到了出发时刻路上经过的所有红绿灯的指示状态。请帮忙计算小明此次回家所需要的时间。 输入格式 输入的第一行包含空格分隔的三个正整数 r、y、g,表示红绿灯的设置。这三个数均不超过 106。 输入的第二行包含一个正整数 n,表示小明总共经过的道路段数和路过的红绿灯数目。 接下来的 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 样例输出 46 样例说明 小明先经过第一段路,用时 10 秒。第一盏红绿灯出发时是红灯,还剩 5 秒;小明到达路口时,这个红绿灯已经变为绿灯,不用等待直接通过。接下来经过第二段路,用时 11 秒。第二盏红绿灯出发时是黄灯,还剩两秒;小明到达路口时,这个红绿灯已经变为红灯,还剩 11 秒。接下来经过第三、第四段路,用时 9 秒。第三盏红绿灯出发时是绿灯,还剩 10 秒;小明到达路口时,这个红绿灯已经变为红灯,还剩两秒。接下来经过最后一段路,用时 3 秒。共计 10+11+11+9+2+3 = 46 秒。 |
解决代码:
#include<stdio.h>
typedef long long LL;
int r,y,g;//红绿灯设置
int n;
int k,t;
LL ans=0;
/*
k=1: 红灯r [0,r)
k=2: 黄灯y [r+g,r+g+y)
k=3: 绿灯g [r,r+g)
以坐标轴来看
即 |__________|__________|___|
红灯 绿灯 黄灯
*/
int judge(LL tt){
if(tt>=0 && tt<r) return 1;
if(tt>=r+g && tt<r+g+y) return 2;
if(tt>=r && tt<r+g) return 3;
}
int main(){
scanf("%d%d%d",&r,&y,&g);
scanf("%d",&n);
for(LL i=0;i<n;i++){
scanf("%d%d",&k,&t);
if(k==0){
ans+=t;
}
else if(k==1){
LL tt=r-t;
tt=(tt+ans)%(r+y+g);
int flag=judge(tt);
if(flag==1){
ans+=r-tt;
}
else if(flag==2){
ans+=r+y+g-tt+r;
}
}
else if(k==2){
LL tt=r+g+y-t;
tt=(tt+ans)%(r+y+g);
int flag=judge(tt);
if(flag==1){
ans+=r-tt;
}
else if(flag==2){
ans+=r+y+g-tt+r;
}
}
else if(k==3){
LL tt=r+g-t;
tt=(tt+ans)%(r+y+g);
int flag=judge(tt);
if(flag==1){
ans+=r-tt;
}
else if(flag==2){
ans+=r+y+g-tt+r;
}
}
}
printf("%lld\n",ans);
return 0;
}
小中大
试题编号: | 201903-1 |
试题名称: | 小中大 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 老师给了你 n 个整数组成的测量数据,保证有序(可能为升序或降序),可能存在重复的数据。请统计出这组测量数据中的最大值、中位数以及最小值,并按照从大到小的顺序输出这三个数。 输入格式 从标准输入读入数据。 第一行输入一个整数 n,在第二行中存在 n 个有序的整数,表示测量数据,可能为升序或降序排列,可能存在连续多个整数相等,整数与整数之间使用空格隔开。 输出格式 输出到标准输出。 包含一行,包括最大值、中位数以及最小值共三个数,并按照从大到小的顺序输出。数据与数据之间使用空格隔开。对于整数请直接输出整数,对于可能出现的分数,请输出四舍五入保留 1 位小数的结果。 样例输入1 3 -1 2 4 样例输出1 4 2 -1 样例解释1 4 为最大值,2 为中位数,−1 为最小值。 样例输入2 4 -2 -1 3 4 样例输出2 4 1 -2 样例解释2 4 为最大值,(−1 + 3) ÷ 2=1 为中位数,−2 为最小值。 提示: |
解决代码;
#include<cstdio>
const int MAXN=100010;
int n;
int arr[MAXN];
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&arr[i]);
}
int mx, mn;
double mid;
if(arr[0]<=arr[n-1]){
mx=arr[n-1];
mn=arr[0];
}
else{
mx=arr[0];
mn=arr[n-1];
}
if(n&1){ //奇数
mid=arr[n/2];
printf("%d %d %d\n",mx, (int)mid, mn);
}
else{ //偶数
mid=(arr[n/2-1]+arr[n/2])*1.0/2;
if((mid-(int)mid)==0){ //整数
printf("%d %d %d\n", mx,(int)mid, mn);
}
else{
printf("%d %.1f %d\n",mx,mid,mn);
}
}
return 0;
}
二十四点
试题编号: | 201903-2 |
试题名称: | 二十四点 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 二十四点是一款著名的纸牌游戏,其游戏的目标是使用 3 个加减乘除运算使得 4张纸牌上数字的运算结果为 24。 定义每一个游戏由 4 个从 1-9 的数字和 3 个四则运算符组成,保证四则运算符将数字两两隔开,不存在括号和其他字符,运算顺序按照四则运算顺序进行。其中加法用符号 + 表示,减法用符号 - 表示,乘法用小写字母 x 表示,除法用符号 / 表示。在游戏里除法为整除,例如 2 / 3 = 0,3 / 2 = 1, 4 / 2 = 2。 老师给了你 n 个游戏的解,请你编写程序验证每个游戏的结果是否为 24 。 输入格式 从标准输入读入数据。第一行输入一个整数 n,从第 2 行开始到第 n + 1 行中,每一行包含一个长度为 7的字符串,为上述的 24 点游戏,保证数据格式合法。 输出格式 输出到标准输出。 包含 n 行,对于每一个游戏,如果其结果为 24 则输出字符串 Yes,否则输出字符串 No。 样例输入 10 9+3+4x3 5+4x5x5 7-9-9+8 5x6/5x4 3+5+7+9 1x1+9-9 1x9-5/9 8/5+6x9 6x7-3x6 6x4+4/5 样例输出 Yes No No Yes Yes No No No Yes Yes 样例解释 9+3+4 × 3 = 24 5+4 × 5 × 5 = 105 7 − 9 − 9+8= −3 5 × 6/5 × 4 = 24 3 + 5 + 7 + 9 = 24 1 × 1+9 − 9=1 1 × 9 − 5/9 = 9 8/5 + 6 × 9 = 55 6 × 7 − 3 × 6 = 24 6 × 4 + 4/5 = 24 提示; |
解决代码;
#include<cstdio>
#include<cstring>
#include<stack>
using namespace std;
int n;
char str[10];
stack<int> num;
stack<char> sign;
int main(){
scanf("%d",&n);
getchar();
for(int i=0;i<n;i++){
gets(str);
while(!num.empty()) num.pop();
while(!sign.empty()) sign.pop();
int j=0;
while(j<strlen(str)){
if(str[j]>'0' && str[j]<='9'){
num.push(str[j]-'0');
}
else{
if(str[j]=='+'){
sign.push('+');
}
else if(str[j]=='-'){ //将减法转换成加法
num.push((str[j+1]-'0')*(-1));
sign.push('+');
j++;
}
else if(str[j]=='x'){ //直接计算乘法
int lhs=num.top();
num.pop();
num.push(lhs*(str[j+1]-'0'));
j++;
}
else if(str[j]=='/'){ //直接计算除法
int lhs=num.top();
num.pop();
num.push(lhs/(str[j+1]-'0'));
j++;
}
}
j++;
}
while(!sign.empty()){ //计算剩余的加法
int rhs=num.top();
num.pop();
int lhs=num.top();
num.pop();
sign.pop();
num.push(lhs+rhs);
}
int ans=num.top();
if(ans==24) printf("Yes\n");
else printf("No\n");
}
return 0;
}