题目 | 类型 |
---|---|
平方和 | 结果填空 |
数列求值 | 结果填空 |
最大降雨量 | 结果填空 |
迷宫 | 结果填空 |
RSA解密 | 结果填空 |
完全二叉树的权值 | 编程题 |
外卖店优先级 | 编程题 |
修改数组 | 编程题 |
糖果 | 编程题 |
组合数问题 | 编程题 |
1. 平方和
- 本题总分:5分
- 问题描述
小明对数位中含有 2、0、1、9 的数字很感兴趣,在 1 到 40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574,平方和是 14362。注意,平方和是指将每个数分别平方后求和。
请问,在 1 到 2019 中,所有这样的数的平方和是多少? - 答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
提示:如果你编写程序计算,发现结果是负的,请仔细检查自己的程序,不要怀疑考场的编程软件。
- 解析
#include<iostream> #include<string> using namespace std; unsigned long long ans; int main() { for (int i = 1; i <= 2019; i++) { string s = to_string(i); for (int j = 0; j < s.length(); j++) { if (s[j] == '2' || s[j] == '0' || s[j] == '1' || s[j] == '9') { ans += i * i; break; } } } cout << ans; return 0; }
- 答案
2658417853
2. 数列求值
- 本题总分:5分
- 问题描述
给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。求第 20190324 项的最后 4 位数字。 - 答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个 4 位整数(提示:答案的千位不为 0),在提交答案时只填写这个整数,填写多余的内容将无法得分。
- 解析
#include<iostream> using namespace std; int main() { int a1, a2, a3, a4; a1 = a2 = a3 = 1; for (int i = 4; i <= 20190324; i++) { a4 = a1 + a2 + a3; a4 %= 10000; a1 = a2; a2 = a3; a3 = a4; } cout << a4; return 0; }
- 答案
4659
3. 最大降雨量
- 本题总分:10分
- 问题描述
由于沙之国长年干旱,法师小明准备施展自己的一个神秘法术来求雨。
这个法术需要用到他手中的 49 张法术符,上面分别写着 1 至 49 这 49 个数字。法术一共持续 7 周,每天小明都要使用一张法术符,法术符不能重复使用。
每周,小明施展法术产生的能量为这周 7 张法术符上数字的中位数。法术施展完 7 周后,求雨将获得成功,降雨量为 7 周能量的中位数。
由于干旱太久,小明希望这次求雨的降雨量尽可能大,请问最大值是多少? - 答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
- 解析
由于降雨量为7周能量的中位数,只与中位数有关,因此尽可能让中位数更大即可。
因此,在每一周中,选取3个小的数字+4个大的数字,那么每周的能量为第一个大数字
例如:
第一周:1,2,3,46,47,48,49。中位数为46
第二周:4,5,6,42,43,44,45。中位数为42
以此类推
因此,降雨量最大值为34 - 答案
34
4. 迷宫
-
本题总分:10分
-
问题描述
下图给出了一个迷宫的平面图,其中标记为 1 的为障碍,标记为 0 的为可以通行的地方。010000
000100
001001
110000迷宫的入口为左上角,出口为右下角,在迷宫中,只能从一个位置走到这个它的上、下、左、右四个方向之一。
对于上面的迷宫,从入口开始,可以按DRRURRDDDR 的顺序通过迷宫,一共 10 步。其中 D、U、L、R 分别表示向下、向上、向左、向右走。
对于下面这个更复杂的迷宫(30 行 50 列),请找出一种通过迷宫的方式,其使用的步数最少,在步数最少的前提下,请找出字典序最小的一个作为答案。请注意在字典序中D<L<R<U。(如果你把以下文字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。在试题目录下有一个文件 maze.txt,内容与下面的文本相同)01010101001011001001010110010110100100001000101010
00001000100000101010010000100000001001100110100101
01111011010010001000001101001011100011000000010000
01000000001010100011010000101000001010101011001011
00011111000000101000010010100010100000101100000000
11001000110101000010101100011010011010101011110111
00011011010101001001001010000001000101001110000000
10100000101000100110101010111110011000010000111010
00111000001010100001100010000001000101001100001001
11000110100001110010001001010101010101010001101000
00010000100100000101001010101110100010101010000101
11100100101001001000010000010101010100100100010100
00000010000000101011001111010001100000101010100011
10101010011100001000011000010110011110110100001000
10101010100001101010100101000010100000111011101001
10000000101100010000101100101101001011100000000100
10101001000000010100100001000100000100011110101001
00101001010101101001010100011010101101110000110101
11001010000100001100000010100101000001000111000010
00001000110000110101101000000100101001001000011101
10100101000101000000001110110010110101101010100001
00101000010000110101010000100010001001000100010101
10100001000110010001000010101001010101011111010010
00000100101000000110010100101001000001000000000010
11010000001001110111001001000011101001011011101000
00000110100010001000100000001000011101000000110011
10101000101000100010001111100010101001010000001000
10000010100101001010110000000100101010001011101000
00111100001000010000000110111000000001000000001011
10000001100111010111010001000110111010101101111000 -
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个字符串,包含四种字母 D、U、L、R,在提交答案时只填写这个字符串,填写多余的内容将无法得分。 -
解析
#include<iostream> #include<string> #include<queue> #include<stack> using namespace std; char map[32][52];//地图,存放0和1 bool vis[32][52];//是否访问过 int record[32][52];//记录如何到达(x, y)点 string s = "DLRU";//方向 int dx[] = { 1, 0, 0,-1 }; int dy[] = { 0,-1, 1, 0 }; struct node { int x; int y; }; void bfs() { queue<node>q; node now, next; now.x = 0; now.y = 0; vis[0][0] = 1; q.push(now); while (!q.empty()) { now = q.front(); q.pop(); for (int i = 0; i < 4; i++) { int x0 = now.x + dx[i]; int y0 = now.y + dy[i]; //如果在范围内,并且没有被访问过,且可以访问 if (x0 >= 0 && x0 < 30 && y0 >= 0 && y0 < 50 && !vis[x0][y0] && map[x0][y0] == '0') { next.x = x0; next.y = y0; vis[x0][y0] = 1; q.push(next); record[x0][y0] = i;//记录如何到达此点 } } } //从出口开始向入口遍历记录,因此放在栈中,便于反向输出 stack<char> st; int x = 29, y = 49; while (x != 0 || y != 0) { st.push(s[record[x][y]]); x = x - dx[record[x][y]]; y = y - dy[record[x][y]]; } //输出 while (!st.empty()) { cout << st.top(); st.pop(); } } int main() { for (int i = 0; i < 30; i++) cin >> map[i]; bfs(); return 0; }
-
答案
DDDDRRURRRRRRDRRRRDDDLDDRDDDDDDDDDDDDRDDRRRURRUURRDDDDRDRRRRRRDRRURRDDDRRRRUURUUUUUUULULLUUUURRRRUULLLUUUULLUUULUURRURRURURRRDDRRRRRDDRRDDLLLDDRRDDRDDLDDDLLDDLLLDLDDDLDDRRRRRRRRRDDDDDDRR
5. RSA解密
- 本题总分:15分
- 问题描述
RSA 是一种经典的加密算法。它的基本加密过程如下。
首先生成两个质数 p, q,令 n = p · q,设 d 与 (p-1) · (q-1) 互质,则可找到 e 使得 d · e 除 (p-1) · (q-1) 的余数为 1。
n, d, e 组成了私钥,n, d 组成了公钥。
当使用公钥加密一个整数 X 时(小于 n),计算 C = Xd mod n,则 C 是加密后的密文。
当收到密文 C 时,可使用私钥解开,计算公式为 X = Ce mod n。
例如,当 p = 5, q = 11, d = 3 时,n = 55, e = 27。
若加密数字 24,得 243 mod 55 = 19。
解密数字 19,得 1927 mod 55 = 24。
现在你知道公钥中 n = 1001733993063167141, d = 212353,同时你截获了别人发送的密文 C = 20190324,请问,原文是多少? - 答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
- 解析
//对n进行因式分解,得到其因子891234941和1123984201 #include<iostream> using namespace std; long long n= 1001733993063167141; long long d = 212353; long long c = 20190324; int main() { for (long long i = 2; i * i < n; i++) { if (n % i == 0) cout << i << " " << n / i; } return 0; }
#include<iostream> using namespace std; long long n = 1001733993063167141; long long d = 212353; long long c = 20190324; long long p = 891234941; long long q = 1123984201; long long phi = (p - 1) * (q - 1); //欧几里得算法求逆元 void Ex_gcd(long long a, long long b, long long& x, long long& y) { if (b == 0) { x = 1; y = 0; return; } long long x1, y1; Ex_gcd(b, a % b, x1, y1); x = y1; y = x1 - (a / b) * y1; } //快速乘求每次的余数 long long quickmul(long long a, long long b) { long long sum = 0; while (b) { if (b % 2 == 1) sum = (sum + a) % n; a = (a + a) % n; b = b / 2; } return sum; } //快速幂 long long quickmod(long long a, long long b) { long long ans = 1; while (b) { if (b % 2 == 1)//末位是1; ans = quickmul(ans, a);//这是直接的回溯法,从最后一位起,如果,如果最后一位是1,则乘a,然后在进行乘以它本身,以为乘1之后一定为偶数,也就是b/2; a = quickmul(a, a); b = b / 2; } return ans; } int main() { long long e, x, y; Ex_gcd(d, (q - 1) * (p - 1), e, y); e = (e + phi) % phi; x = quickmod(c, e); cout << x; return 0; }
- 答案
579706994112328949
引用:https://www.jianshu.com/p/ec919a5d4c90
6. 完全二叉树的权值
- 时间限制:1.0s
- 内存限制:256.0MB
- 本题总分:15分
- 问题描述
给定一棵包含 N 个节点的完全二叉树,树上每个节点都有一个权值,按从上到下、从左到右的顺序依次是 A1, A2, · · · AN,如下图所示:
现在小明要把相同深度的节点的权值加在一起,他想知道哪个深度的节点权值之和最大?如果有多个深度的权值和同为最大,请你输出其中最小的深度。
注:根的深度是 1。 - 输入格式
第一行包含一个整数 N。
第二行包含 N 个整数 A1, A2, · · · AN 。 - 输出格式
输出一个整数代表答案。 - 样例输入
7
1 6 5 4 3 2 1 - 样例输出
2 - 评测用例规模与约定
对于所有评测用例,1 ≤ N ≤ 100000, 100000 ≤ Ai ≤ 100000。
- 答案
#include<iostream> #include<cmath> using namespace std; #define ll long long ll sum; int n, ans, deep; int main() { cin >> n; deep = 1; //n个结点对应有log(2)(n+1)层 while (deep <= log(n+1)/log(2)) { int num; ll temp = 0; //一层一层输入计算总和 for (int i = 0; i < pow(2, deep - 1); i++) { cin >> num; temp += num; } //如果比目前的sum更大,则更新sum和层数 if (temp > sum) { sum = temp; ans = deep; } deep++; } cout << ans; return 0; }
7. 外卖店优先级
- 时间限制:1.0s
- 内存限制:256.0MB
- 本题总分:20分
- 问题描述
“饱了么”外卖系统中维护着 N 家外卖店,编号 1 ∼ N。每家外卖店都有一个优先级,初始时 (0 时刻) 优先级都为 0。
每经过 1 个时间单位,如果外卖店没有订单,则优先级会减少 1,最低减到 0;而如果外卖店有订单,则优先级不减反加,每有一单优先级加 2。
如果某家外卖店某时刻优先级大于 5,则会被系统加入优先缓存中;如果优先级小于等于 3,则会被清除出优先缓存。
给定 T 时刻以内的 M 条订单信息,请你计算 T 时刻时有多少外卖店在优先缓存中。 - 输入格式
第一行包含 3 个整数 N、M 和 T。
以下 M 行每行包含两个整数 ts 和 id,表示 ts 时刻编号 id 的外卖店收到一个订单。 - 输出格式
输出一个整数代表答案。 - 样例输入
2 6 6
1 1
5 2
3 1
6 2
2 1
6 2 - 样例输出
1 - 样例解释
6 时刻时,1 号店优先级降到 3,被移除出优先缓存;2 号店优先级升到 6,加入优先缓存。所以是有 1 家店 (2 号) 在优先缓存中。 - 评测用例规模与约定
对于 80% 的评测用例,1 ≤ N, M, T ≤ 10000。
对于所有评测用例,1 ≤ N, M, T ≤ 100000,1 ≤ ts ≤ T,1 ≤ id ≤ N。
- 答案
#include<iostream> #include<algorithm> #include<map> using namespace std; int store[100005];//用于存储商店的优先级 int ans;//用于存储答案 struct node { int ts; int id; }order[100005];//用于存储菜单数据 //按照ts进行排序 bool cmp(node a, node b) { if (a.ts < b.ts) return 1; else return 0; } int main() { int n, m, t; map<int, bool> map; //输入 cin >> n >> m >> t; for (int i = 0; i < m; i++) cin >> order[i].ts >> order[i].id; //初始化map for (int i = 0; i < n; i++) map[i] = false; //按照时间进行排序 sort(order, order + m, cmp); int pre = 0; for (int i = 0; i < m; i++) { int now = order[i].ts; int idx = order[i].id - 1; store[idx] -= now - pre; if (store[idx] < 0) store[idx] = 0; store[idx] += 2; if (store[idx] >= 5) map[idx] = true; else map[idx] = false; pre = now; } //筛选 for (int i = 0; i < n; i++) { if (map[i] == true) ans++; } cout << ans; return 0; }
8. 修改数组
- 时间限制:1.0s
- 内存限制:256.0MB
- 本题总分:20分
- 问题描述
给定一个长度为 N 的数组 A = [A1, A2, · · · AN],数组中有可能有重复出现的整数。
现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改A2, A3, · · · , AN。
当修改 Ai 时,小明会检查 Ai 是否在 A1 ∼ Ai-1 中出现过。如果出现过,则小明会给 Ai 加上 1 ;如果新的 Ai 仍在之前出现过,小明会持续给 Ai 加 1 ,直到 Ai 没有在 A1 ∼ Ai-1 中出现过。
当 AN 也经过上述修改之后,显然 A 数组中就没有重复的整数了。
现在给定初始的 A 数组,请你计算出最终的 A 数组。 - 输入格式
第一行包含一个整数 N。
第二行包含 N 个整数 A1, A2, · · · , AN 。 - 输出格式
输出 N 个整数,依次是最终的 A1, A2, · · · , AN 。 - 样例输入
5
2 1 1 3 4 - 样例输出
2 1 3 4 5 - 评测用例规模与约定
对于 80% 的评测用例,1 ≤ N ≤ 10000。
对于所有评测用例,1 ≤ N ≤ 100000,1 ≤ Ai ≤ 1000000。
- 答案
#include<iostream> using namespace std; int a[100005]; bool vis[1000005]; int main() { int n, num; cin >> n; for (int i = 0; i < n; i++) { cin >> num; if (vis[num] == 0) { a[i] = num; vis[num] = 1; } else { while (vis[num] == 1) { num++; } a[i] = num; vis[num] = 1; } } for (int i = 0; i < n; i++) cout << a[i] << " "; return 0; }
9. 糖果
- 时间限制:1.0s
- 内存限制:256.0MB
- 本题总分:25分
- 问题描述
糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种口味编号 1 ∼ M。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 K 颗一包整包出售。
幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。
给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。 - 输入格式
第一行包含三个整数 N、M 和 K。
接下来 N 行每行 K 个整数 T1, T2, · · · , TK,代表一包糖果的口味。 - 输出格式
一个整数表示答案。如果小明无法品尝所有口味,输出 -1。 - 样例输入
6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2 - 样例输出
2 - 评测用例规模与约定
对于 30% 的评测用例,1 ≤ N ≤ 20 。
对于所有评测样例,1 ≤ N ≤ 100,1 ≤ M ≤ 20,1 ≤ K ≤ 20,1 ≤ Ti ≤ M。
- 答案
#include <iostream> #include <set> #include <string> #include <algorithm> #define For(i,a,b) for(register int i=(a);i<=(b);++i) #define Rep(i,a,b) for(register int i=(a);i>=(b);--i) #define Mst(a,b) memset(a,(b),sizeof(a)) using namespace std; int dp[1 << 20]; //二进制状态压缩 int a[105]; int main() { //freopen("in.txt","r",stdin); int m, n, k; while (scanf("%d%d%d", &n, &m, &k) != EOF) { set<int> v; //记录n包中所有糖果的种类数 memset(dp, 0x3f, sizeof(int) * (1 << m)); //初始化 dp[0] = 0; For(i, 1, n) { int x = 0, y; For(j, 1, k) { scanf("%d", &y); --y; v.insert(y); x |= (1 << y); } a[i] = x; //x的二进制形式第i位为1代表这个集合中有第i+1种糖果 dp[x] = 1;//这种状态只需要第i包糖果1包就可以达到 } if ((int)v.size() < m) //把n包唐都买了也吃不到m中糖果 { printf("-1\n"); continue; } int ed = (1 << m) - 1; //目标状态 For(i, 1, n) { For(state, 0, ed) { if (dp[state] > 200) continue; //用已有的状态去更新加上第i包糖果后的状态 int to = a[i] | state; dp[to] = min(dp[to], 1 + dp[state]); } } printf("%d\n", dp[ed]); } return 0; }
引用:https://blog.csdn.net/qq_40531479/article/details/89041933
10. 组合数问题
- 时间限制:1.0s
- 内存限制:256.0MB
- 本题总分:25分
- 问题描述
给 n, m, k,求有多少对 (i, j) 满足 1 ≤ i ≤ n, 0 ≤ j ≤ min(i, m) 且 C(i, j) ≡0(mod k),k 是质数。其中 C(i, j) 是组合数,表示从 i 个不同的数中选出 j 个组成一个集合的方案数。 - 输入格式
第一行两个数 t, k,其中 t 代表该测试点包含 t 组询问,k 的意思与上文中相同。
接下来 t 行每行两个整数 n, m,表示一组询问。 - 输出格式
输出 t 行,每行一个整数表示对应的答案。由于答案可能很大,请输出答案除以 109 + 7 的余数。 - 样例输入
1 2
3 3 - 样例输出
1 - 样例说明
在所有可能的情况中,只有 C(1, 2) = 2 是 2 的倍数。 - 样例输入
2 5
4 5
6 7 - 样例输出
0
7 - 样例输入
3 23
23333333 23333333
233333333 233333333
2333333333 2333333333 - 样例输出
851883128
959557926
680723120 - 数据规模和约定
对于所有评测用例,1 ≤ k ≤ 108, 1 ≤ t ≤ 105, 1 ≤ n, m ≤ 1018,且 k 是质数。
评测时将使用 10 个评测用例测试你的程序,每个评测用例的限制如下:
- 答案
#include<iostream> #include<algorithm> using namespace std; #define ll long long ll mod = 1000000007; ll mat[1000][1000]; ll Rcombinat(ll m, ll n) { if (mat[m][n] != 0) return mat[m][n]; if (n == 0 || m == n) { mat[m][n] = 1; return 1; } mat[m - 1][n - 1] = Rcombinat(m - 1, n - 1); mat[m - 1][n] = Rcombinat(m - 1, n); mat[m][n] = mat[m - 1][n - 1] + mat[m - 1][n]; return mat[m][n]; } int main() { ll t, k; cin >> t >> k; while (t--) { ll n, m, ans = 0; cin >> n >> m; for (ll i = 1; i <= n; i++) { for (ll j = 0; j <= min(i, m); j++) { memset(mat, 0, sizeof(mat)); ll res = Rcombinat(i, j); if (res % k == 0) ans++; } } cout << ans%mod << endl; } return 0; }