目录
试题 A: 整数范围
【问题描述】
用 8 位二进制(一个字节)来表示一个非负整数,表示的最小值是 0,则一般能表示的最大值是多少?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
【问题分析】
计算机常识题, 长度为n的2进制数用来表示一个无符号整数,最大值为 2 n − 1 2^n-1 2n−1,所以答案为255
试题 B: 纯质数
【问题描述】
如果一个正整数只有 1 和它本身两个约数,则称为一个质数(又称素数)。
前几个质数是:2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, · · · 。
如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如:2, 3, 5, 7, 23, 37 都是纯质数,而 11, 13, 17, 19, 29, 31 不是纯质数。
当然 1, 4, 35 也不是纯质数。 请问,在 1 到 20210605 中,有多少个纯质数?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
【问题分析】
先将1到20210605中所有的质数筛选出来,使用is_prime数组标记是否为质数。
遍历所有质数(可在筛选质数的同时遍历),判断该质数每个数位是否为质数。
【解题代码】
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 20210610;
bool is_prime[N];
int main() {
int n = 20210605;
is_prime[0] = is_prime[1] = 1;
int cnt = 0;
for(int i = 2;i <= n;i ++) {
if(!is_prime[i]) {
for(int j = i + i;j <= n;j += i) {
is_prime[j] = 1;
}
int x = i;
cnt ++;
while(x) {
int t = x % 10;
x /= 10;
if(is_prime[t]) {
cnt --;
break;
}
}
}
}
printf("%d", cnt); // 1903
return 0;
}
试题 C: 完全日期
【问题描述】
如果一个日期中年月日的各位数字之和是完全平方数,则称为一个完全日期。
例如:2021 年 6 月 5 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 5 = 16,而 16 是一个完全平方数,它是 4 的平方。所以 2021 年 6 月 5 日是一个完全日期。
例如:2021 年 6 月 23 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 2 + 3 = 16,是一个完全平方数。所以 2021 年 6 月 23 日也是一个完全日期。
请问,从 2001 年 1 月 1 日到 2021 年 12 月 31 日中,一共有多少个完全日期?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
【问题分析】
完全平方数指的是能表示成某个整数的平方的数,因为日期位数为8位,八位数字之和小于9的平方,所以我们先算出从1到9各数的平方值存入is_square数组,表示一个数是否为完全平方数。
遍历20010101到20211231间的每个数,验证其作为日期的合法性,如合法就将日期的每个数位进行想加,判断和是否为完全平方数。
【解题代码】
#include <iostream>
#include <cstdio>
using namespace std;
int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool is_square[100];
bool is_leap(int x) {
return (x % 4 == 0 && x % 100 == 0) || x % 400 == 0;
}
bool check(int x) {
int y = x / 10000, m = x % 10000 / 100, d = x % 100;
days[2] = 28 + is_leap(y);
if(m > 12 || m < 1) return 0;
if(d > days[m] || d < 1) return 0;
return 1;
}
int main() {
int cnt = 0;
for(int i = 1;i <= 9;i ++) {
is_square[i * i] = 1;
}
for(int i = 20010101;i <= 20211231;i ++) {
if(check(i)) {
int x = i;
int sum = 0;
while(x) {
int t = x % 10;
x /= 10;
sum += t;
}
if(is_square[sum]) cnt ++;
}
}
printf("%d", cnt); // 977
return 0;
}
试题 D: 最小权值
【问题描述】
对于一棵有根二叉树 T,小蓝定义这棵树中结点的权值 W(T) 如下:
空子树的权值为 0。
如果一个结点 v 有左子树 L, 右子树 R,分别有 C(L) 和 C® 个结点,则 W(v) = 1 + 2W(L) + 3W® + (C(L)) 2 C®。
树的权值定义为树的根结点的权值。
小蓝想知道,对于一棵有 2021 个结点的二叉树,树的权值最小可能是多少?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
【问题分析】
【解题代码】
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 2030;
long long w[N];
int main() {
memset(w, 0x3f, sizeof w);
w[0] = 0;
for(int i = 1;i <= 2021;i ++) {
for(int l = 0;l <= i - 1;l ++) {
w[i] = min(w[i], 1 + 2 * w[l] + 3 * w[i - 1 - l] + l * l * (i - 1 - l));
}
}
printf("%lld", w[2021]);
return 0;
}
试题 E: 大写
【问题描述】
给定一个只包含大写字母和小写字母的字符串,请将其中所有的小写字母 转换成大写字母后将字符串输出。
【输入格式】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一 个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
【输出格式】
输出转换成大写后的字符串。
【样例】
【样例输入】 LanQiao
【样例输出】 LANQIAO
【问题分析】
遍历字符串中的每个字符做判断
【解题代码】
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
string a;
cin >> a;
int t = 'A' - 'a';
for(int i = 0;i < a.size();i ++) {
if(a[i] >= 'a' && a[i] <= 'z') a[i] += t;
}
cout << a;
return 0;
}
试题 F: 123
【问题描述】
小蓝发现了一个有趣的数列,这个数列的前几项如下:
1, 1, 2, 1, 2, 3, 1, 2, 3, 4, …
小蓝发现,这个数列前 1 项是整数 1,接下来 2 项是整数 1 至 2,接下来 3 项是整数 1 至 3,接下来 4 项是整数 1 至 4,依次类推。
小蓝想知道,这个数列中,连续一段的和是多少。
【输入格式】
输入的第一行包含一个整数 T,表示询问的个数。
接下来 T 行,每行包含一组询问,其中第 i 行包含两个整数 l i l_i li 和 r i r_i ri,表示询问数列中第 l i l_i li 个数到第 r i r_i ri 个数的和。
【输出格式】
输出 T 行,每行包含一个整数表示对应询问的答案。
【样例】
【样例输入】
3
1 1
1 3
5 8
【样例输出】
1
4
8
【问题分析】
1、因为题目的要求为“求出数列中第 l i l_i li 个数到第 r i r_i ri 个数的和”,不难想到可以使用前缀和来求解,但是本题数据范围很大单独靠前缀和显然无法解决,故因想办法降低算法复杂度;
2、通过观察不难发现,题目中给出的数列中的每个数可以描述为第n部分的第m个数
其中第N部分指的是数列中的这一部分的数为1至n,由此还可以得出第n部分的总和为 n ( n + 1 ) / 2 n(n + 1) / 2 n(n+1)/2
3、因为第 i 个数可以表示数列中的第n部分的第m个数,所以数列前 i 项的和可以表示为数列前n-1部分的和 + 数字1到m的和(也就等于数列第m部分的和)
4、定义数组a[], s[],使用数组a[n]表示数列第n部分的和,s[n]表示数列前n部分的和
【解题代码】
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 1414220;
// 因为l,r <= 1e12,数列各部分数字的数量为首项和公差都为1的等差序列
// 所以N应满足:N(N+1)/2 > 1e12
long long s[N], a[N];
long long cal(long long x) {
// 使用2分加快寻找x所处部分的前一部分是哪个部分
int l = 0, r = N;
while(l < r) {
int mid = (l + r + 1) / 2;
// 数列各部分数字的数量为首项和公差都为1的等差序列
// 所以前n部分数字的数量和就为n(n+1)/2,也就是a[n]
if(a[mid] > x) r = mid - 1;
else l = mid;
}
return s[l] + a[x - a[l]];
}
int main() {
int t;
scanf("%d", &t);
for(int i = 1;i < N;i ++) {
a[i] = a[i - 1] + i;
s[i] = s[i - 1] + a[i];
}
while(t --) {
long long l, r;
scanf("%lld %lld", &l, &r);
printf("%lld\n", cal(r) - cal(l - 1));
}
return 0;
}
试题 G: 和与乘积
【问题描述】
给定一个数列 A = ( a 1 , a 2 , ⋅ ⋅ ⋅ , a n ) A = (a_1, a_2, ··· , a_n) A=(a1,a2,⋅⋅⋅,an),问有多少个区间 [L, R] 满足区间内元素
的乘积等于他们的和,即 a L ⋅ a L + 1 ⋅ ⋅ ⋅ a R = a L + a L + 1 + ⋅ ⋅ ⋅ + a R a_L · a_{L+1} ··· a_R = a_L + a_{L+1} + · · · + a_R aL⋅aL+1⋅⋅⋅aR=aL+aL+1+⋅⋅⋅+aR。
【输入格式】
输入第一行包含一个整数 n,表示数列的长度。
第二行包含 n 个整数,依次表示数列中的数 a 1 , a 2 , ⋅ ⋅ ⋅ , a n a_1, a_2, ··· , a_n a1,a2,⋅⋅⋅,an。
【输出格式】
输出仅一行,包含一个整数表示满足如上条件的区间的个数。
【样例】
【样例输入】
4
1 3 2 2
【样例输出】
6
【问题分析】
【解题代码】
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 200010;
long long s[N], cnt[N], num[N];
int main() {
int n, idx = 1;
scanf("%d", &n);
for(int i = 0;i < n;i ++) {
int x;
scanf("%d", &x);
if(x == 1) {
s[idx] ++;
cnt[idx] ++;
}
else {
s[idx] += s[idx - 1] + x;
num[idx] = x;
idx ++;
}
}
long long res = n, sum = s[idx - 1] + cnt[idx];
for(int i = 1;i < idx;i ++) {
long long t = num[i];
for(int j = i + 1;j < idx;j ++) {
t *= num[j];
if(t > sum) break;
long long tsum = s[j] - s[i - 1] - cnt[i];
long long d = t - tsum;
if(d < 0) continue;
else if(d == 0) res ++;
else if(d <= cnt[i] + cnt[j + 1]) {
long long lcnt = min(cnt[i], d), rcnt = min(cnt[j + 1], d);
res += lcnt + rcnt - d + 1;
}
}
}
printf("%lld", res);
return 0;
}
试题 H: 巧克力
【问题描述】
小蓝很喜欢吃巧克力,他每天都要吃一块巧克力。
一天小蓝到超市想买一些巧克力。超市的货架上有很多种巧克力,每种巧
克力有自己的价格、数量和剩余的保质期天数,小蓝只吃没过保质期的巧克力,
请问小蓝最少花多少钱能买到让自己吃 x 天的巧克力。
【输入格式】
输入的第一行包含两个整数 x, n,分别表示需要吃巧克力的天数和巧克力的种类数。
接下来 n 行描述货架上的巧克力,其中第 i 行包含三个整数 a i a_i ai, b i b_i bi, c i c_i ci,表示第 i 种巧克力的单价为 a i a_i ai,保质期还剩 b i b_i bi 天(从现在开始的 b i b_i bi 天可以吃),数量为 c i c_i ci。
【输出格式】
输出一个整数表示答案。
【样例】
【样例输入】
10 3
1 6 5
2 7 3
3 10 10
【样例输出】
18
【问题分析】
题目要求使用最少的钱可以在第x天吃到巧克力
那么可以从第x天开始逆序处理,优先保证第x天有巧克力,在所有满足保质期大于等于x天的巧克力中选择价格最低的,然后依次按第x-1, x-2, … , 1天
具体步骤:
1、将读取到的商品信息,按保质期从大到小排序;
2、从第x天开始逆序处理,处理到第 i 天时就把保质期时间大于等于 i 的商品加入到优先队列中,优先队列中保证队首元素为保质期时间大于等于 i,价格最小的商品;
3、去除队首商品,购买一件后如商品数量仍大于等于0,就将商品再加回优先队列。
【解题代码】
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <queue>
#define fi first
#define se second
using namespace std;
typedef pair<int, pair<int, int>> PIII;
const int N = 100010;
priority_queue<PIII, vector<PIII>, greater<PIII>> q;
PIII g[N];
bool cmp(PIII a, PIII b) {
return a.se.fi > b.se.fi;
}
int main() {
int n, x;
scanf("%d %d", &x, &n);
for(int i = 0;i < n;i ++) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
g[i] = {a, {b, c}};
}
sort(g, g + n, cmp);
int idx = 0;
long long res = 0;
for(int i = x;i > 0;i --) {
for(;idx < n && g[idx].se.fi >= i;idx ++) {
q.push(g[idx]);
}
if(q.empty()) {
res = -1;
break;
}
PIII t = q.top();
q.pop();
res += t.fi;
if(-- t.se.se > 0) {
q.push(t);
}
}
printf("%lld", res);
return 0;
}
试题 I: 翻转括号序列
【问题描述】
给定一个长度为 n 的括号序列,要求支持两种操作:
1.将 [ L i L_i Li, R i R_i Ri] 区间内(序列中的第 L i L_i Li个字符到第 R i R_i Ri个字符)的括号全部翻转(左括号变成右括号,右括号变成左括号)。
2.求出以 L i L_i Li为左端点时,最长的合法括号序列对应的 R i R_i Ri (即找出最大的 R i R_i Ri使 [Li, R i R_i Ri] 是一个合法括号序列)。
【输入格式】
输入的第一行包含两个整数 n, m,分别表示括号序列长度和操作次数。
第二行包含给定的括号序列,括号序列中只包含左括号和右括号。
接下来 m 行,每行描述一个操作。如果该行为 “1 L i L_i Li R i R_i Ri”,表示第一种操作,区间为 [ L i L_i Li, R i R_i Ri] ;如果该行为 “2 L i L_i Li” 表示第二种操作,左端点为 L i L_i Li。
【输出格式】
对于每个第二种操作,输出一行,表示对应的 R i R_i Ri。如果不存在这样的 R i R_i Ri,请输出 0。
【样例】
【样例输入】
7 5
((())()
2 3
2 2
1 3 5
2 3
2 1
【样例输出】
4
7
0
0
【问题分析】
【解题代码】
试题 J: 异或三角
【问题描述】
给定 T 个数 n 1 , n 2 , ⋅ ⋅ ⋅ , n T n_1, n_2, · · · , n_T n1,n2,⋅⋅⋅,nT,对每个 n i n_i ni 请求出有多少组 a, b, c 满足:
- 1 ≤ a , b , c ≤ n i 1 ≤ a, b, c ≤ n_i 1≤a,b,c≤ni;
- a ⊕ b ⊕ c = 0,其中 ⊕ 表示二进制按位异或;
- 长度为 a, b, c 的三条边能组成一个三角形。
【输入格式】
输入的第一行包含一个整数 T。
接下来 T 行每行一个整数,分别表示 n 1 , n 2 , ⋅ ⋅ ⋅ , n T n_1, n_2, · · · , n_T n1,n2,⋅⋅⋅,nT。
【输出格式】
输出 T 行,每行包含一个整数,表示对应的答案。
【样例】
【样例输入】
2
6
114514
【样例输出】
6
11223848130
【问题分析】
【解题代码】