⏰总用时:245/240 🎯总分:59.1/150
题号 |
时间 |
结果 |
满分 |
难度 |
备注 |
1 |
5 |
❌ |
5 |
🌕 |
🔸 计算完一定要带入样例检验,漏加了 1 ❗❗❗ |
2 |
15 |
✅ |
7 |
🌕 |
|
3 |
40 |
✅ |
9 |
🌕 |
|
4 |
10 |
✅ |
13 |
🌕 |
|
5 |
5 |
✅ |
11 |
🌕 |
|
6 |
60 |
✅ |
17 |
🌕 |
🔹 注意 scanf,printf 格式化输入输出的使用 |
7 |
25 |
❌ |
19 |
🌑 |
🔸 三维差分数组 🔸 二分法查找 🔸 压缩数组 🔸 memcpy()用法 |
8 |
25 |
10% |
21 |
🌓 |
🔹 【dfs】每次遍历一整块岛屿,并标记其是否能幸存 🔹 用%c时小心读入空行等 🔹 注意代码中变量类型的错误 |
9 |
10 |
❌ |
23 |
🌓 |
🔸 暴力 |
10 |
50 |
❌ |
25 |
|
|
1 【填空】分数
题目
1/1+1/2+1/4+1/8+……
每项是前一项的一半,如果一共有 20 项,求这个和是多少,结果用分数表示出来。
类似:3/2,当然,这只是加了前 2 项而已。分子分母要求互质。
解析
注意检验,前面还加了一个 1 ❗❗❗
1
2
3
4
5
6
7
8
9
|
#include <iostream>
using namespace std;
int main()
{
// 请在此输入您的代码
// 1+(1-1/2^19)
cout<<"1048575/524288";
return 0;
}
|
2 【填空】星期一
题目
整个 20 世纪(1901 年 1 月 1 日至 2000 年 12 月 31 日之间),一共有多少个星期一?(不要告诉我你不知道今天是星期几)
解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#include <bits/stdc++.h>
using namespace std;
int main(){
int ans,sum=0;
for(int i=1901;i<=2000;i++){ // 计算总天数,最后一天是星期六
if((i%4==0 && i%100!=0) || i%400==0) // 这是闰年
sum+=366;
else sum+=365; // 这不是闰年
}
ans=sum/7;
if(sum%7==5) ans++;
cout<<ans;
return 0;
}
|
3 【填空】乘积尾0
题目
如下的 10 行数据,每行有 10 个整数,请你求出它们的乘积的末尾有多少个零?
1
2
3
4
5
6
7
8
9
10
|
5650 4542 3554 473 946 4114 3871 9073 90 4329
2758 7949 6113 5659 5245 7432 3051 4434 6704 3594
9937 1173 6866 3397 4759 7557 3070 2287 1453 9899
1486 5722 3135 1170 4014 5510 5120 729 2880 9019
2049 698 4582 4346 4427 646 9742 7340 1230 7683
5693 7015 6887 7381 4172 4341 2909 2027 7355 5649
6701 6645 1671 5978 2704 9926 295 3125 3878 6785
2066 4247 4800 1578 6652 4616 1113 6205 3264 2915
3966 5291 2904 1285 2193 1428 2265 8730 9436 7074
689 5510 8243 6114 337 4096 8199 7313 3685 211
|
解析
🟠 注意 10=2*5
,只用看这100个数中因数 2 和 5 的个数分别为多少,不用乘出来。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include <bits/stdc++.h>
using namespace std;
int main(){
int x=0,y=0,t,ans;
for(int i=0;i<100;i++){
cin>>t;
while(t%2==0){ // 计算 2 的个数
x++;t/=2;
}
while(t%5==0){ // 计算 5 的个数
y++;t/=5;
}
}
ans=min(x,y);
cout<<ans;
return 0;
}
|
4 【填空】第几个幸运数
题目
到 X 星球旅行的游客都被发给一个整数,作为游客编号。
X 星的国王有个怪癖,他只喜欢数字 3,5 和 7。国王规定,游客的编号如果只含有因子:3,5,7 就可以获得一份奖品。
我们来看前 10 个幸运数字是: 3, 5, 7, 9, 15, 21, 25, 27, 35, 45 。因而第 11 个幸运数字是: 49 。
小明领到了一个幸运数字 59084709587505,他去领奖的时候,人家要求他准确地说出这是第几个幸运数字,否则领不到奖品。
请你帮小明计算一下,59084709587505 是第几个幸运数字。
解析
🟠 直接遍历,注意每次遍历后 i, j, k 分别乘 3, 5, 7 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n=59084709587505;
int cnt=0;
for(ll i=1;i<=n;i*=3){
for(ll j=1;i*j<=n;j*=5){
for(ll k=1;i*j*k<=n;k*=7)
cnt++;
}
}
cout<<cnt-1; // 要减去 1
return 0;
}
|
5 【填空】打印图形
题目
如下的程序会在控制台绘制分形图。
当 n=1,2,3 的时候,输出如下: 请仔细分析程序,并填写划线部分缺少的代码。
解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
#include <stdio.h>
#include <stdlib.h>
void show(char* buf, int w){
int i,j;
for(i=0; i<w; i++){
for(j=0; j<w; j++){
printf("%c", buf[i*w+j]==0? ' ' : 'o');
}
printf("\n");
}
}
void draw(char* buf, int w, int x, int y, int size){
if(size==1){
buf[y*w+x] = 1;
return;
}
int n = size/3 ; //填空
draw(buf, w, x, y, n);
draw(buf, w, x-n, y ,n);
draw(buf, w, x+n, y ,n);
draw(buf, w, x, y-n ,n);
draw(buf, w, x, y+n ,n);
}
int main()
{
int N ;
scanf("%d",&N);
int t = 1;
int i;
for(i=0; i<N; i++) t *= 3; // 最长的一行圆的个数
char* buf = (char*)malloc(t*t);
for(i=0; i<t*t; i++) buf[i] = 0; // 初始化
draw(buf, t, t/2, t/2, t);
show(buf, t);
free(buf);
return 0;
}
|
6 航班时间
题目
不久后小 h 的女朋友去中东交换。小 h 并不知道中东与北京的时差。但是小 h 得到了女朋友来回航班的起降时间。小 h 想知道女朋友的航班飞行时间是多少。
对于一个可能跨时区的航班,给定来回程的起降时间。假设飞机来回飞行时间相同,求飞机的飞行时间。
输入描述
一个输入包含多组数据。
输入第一行为一个正整数 n ,表示输入数据组数。
每组数据包含两行,第一行为去程的 起降 时间,第二行为回程的 起降 时间。
输出描述
对于每一组数据输出一行一个时间 hh:mm:ss,表示飞行时间为 hh 小时 mm 分 ss 秒。
注意,当时间为一位数时,要补齐前导零。如三小时四分五秒应写 03:04:05。
解析
🟠 注意 scanf,printf 格式化输入输出的使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <bits/stdc++.h>
using namespace std;
int getTime(){
int h1,h2,m1,m2,s1,s2,d=0,t;
// 注意这种格式化输入方法!!!
scanf("%d:%d:%d %d:%d:%d (+%d)",&h1,&m1,&s1,&h2,&m2,&s2,&d);
// 都换算成秒,不能用时分秒分别计算,容易出错!!!
t=d*24*60*60+(h2*3600+m2*60+s2)-(h1*3600+m1*60+s1);
return t;
}
int main(){
int n,t1,t2,t;
scanf("%d",&n);
for(int i=0;i<n;i++){
t1=getTime();
t2=getTime();
t=(t1+t2)/2;
printf("%02d:%02d:%02d\n",t/3600,t/60%60,t%60);
}
return 0;
}
|
7 三体攻击
题目
三体人将对地球发起攻击。为了抵御攻击,地球人派出 A × B × C 艘战舰,在太空中排成一个 A 层 B 行 C 列的立方体。其中,第 i 层第 j 行第 k 列的战舰(记为战舰 ( i, j, k ))的生命值为 d( i, j, k)。
三体人将会对地球发起 m 轮"立方体攻击",每次攻击会对一个小立方体中的所有战舰都造成相同的伤害。具体地,第 t 轮攻击用 7 个参数 lat, rat, lbt, rbt, lct, rct, ht 描述;
所有满足 i ∈ [ lat, rat ], j ∈ [ lbt, rbt ], k ∈ [ lct, rct ] 的战舰 ( i, j, k ) 会受到 ht 的伤害。如果一个战舰累计受到的总伤害超过其防御力,那么这个战舰会爆炸。
地球指挥官希望你能告诉他,第一艘爆炸的战舰是在哪一轮攻击后爆炸的。
输入描述
第一行包括 4 个正整数 A, B, C, m;
第二行包含 A × B × C 个整数,其中第 (( i − 1)×B + ( j − 1)) × C + ( k − 1)+1 个数为 d( i, j, k) ;
第 3 到第 m + 2 行中,第 ( t − 2) 行包含 7 个正整数 lat, rat, lbt, rbt, lct, rct, ht 。
其中, A × B × C ≤ $10^6$, m ≤ $10^6$, 0 ≤ d( i, j, k),ht ≤ $10^6$, 。
输出描述
输出第一个爆炸的战舰是在哪一轮攻击后爆炸的。保证一定存在这样的战舰。
解析
🟠 【三维差分数组】
✔ 差分数组递推式
1
|
b[i][j][k]=s[i][j][k]−s[i−1][j][k]−s[i][j−1][k]−s[i][j][k−1]+s[i−1][j−1][k]+s[i−1][j][k−1]+s[i][j−1][k−1]−s[i−1][j−1][k−1]
|
✔ 三维区间修改
1
2
3
4
5
6
7
8
9
10
11
|
b[x1][y1][z1] += c;
b[x2 + 1][y1][z1] -= c;
b[x1][y1][z2 + 1] -= c;
b[x1][y2 + 1][z1] -= c;
b[x2 + 1][y1][z2 + 1] += c;
b[x2 + 1][y2 + 1][z1] += c;
b[x1][y2 + 1][z2 + 1] += c;
b[x2 + 1][y2 + 1][z2 + 1] -= c;
|
✔ 求前缀和
1
|
s[i][j][k] = s[i-1][j][k]+s[i][j-1][k]+s[i][j][k-1]-s[i-1][j-1][k]-s[i-1][j][k-1]-s[i][j-1][k-1]+s[i-1][j-1][k-1]+b[i][j][k]
|
🟡 【二分法】查找
🟢 把三维数组压缩为一维
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2000010;
int A, B, C, m; // 层,行,列, 攻击轮数
LL s[N], b[N], bp[N]; // 生命值, 差分数组,备份差分数组
int op[N / 2][7]; // 攻击范围及伤害
// 差分数组八个方向偏移量
int d[8][4] =
{
{0, 0, 0, 1},
{0, 0, 1, -1},
{0, 1, 0, -1},
{0, 1, 1, 1},
{1, 0, 0, -1},
{1, 0, 1, 1},
{1, 1, 0, 1},
{1, 1, 1, -1},
};
// 压维映射函数
int get(int i, int j, int k)
{
return (i * B + j) * C + k;
}
bool check(int mid)
{
memcpy(b, bp, sizeof b);
for(int i = 1; i <= mid; i ++ )
{
int x1 = op[i][0], x2 = op[i][1], y1 = op[i][2], y2 = op[i][3], z1 = op[i][4], z2 = op[i][5], h = op[i][6];
b[get(x1, y1, z1)] += -h; // 伤害为负
b[get(x1, y1, z2 + 1)] -= -h;
b[get(x1, y2 + 1, z1)] -= -h;
b[get(x1, y2 + 1, z2 + 1)] += -h;
b[get(x2 + 1, y1, z1)] -= -h;
b[get(x2 + 1, y1, z2 + 1)] += -h;
b[get(x2 + 1, y2 + 1, z1)] += -h;
b[get(x2 + 1, y2 + 1, z2 + 1)] -= -h;
}
// 求前缀和
// s[i][j][k] = s[i-1][j][k]+s[i][j-1][k]+s[i][j][k-1]-s[i-1][j-1][k]-s[i-1][j][k-1]-s[i][j-1][k-1]+s[i-1][j-1][k-1]+b[i][j][k]
memset(s, 0, sizeof s);
for(int i = 1; i <= A; i ++ )
for(int j = 1; j <= B; j ++ )
for(int k = 1; k <= C; k ++ )
{
s[get(i, j ,k)] = b[get(i, j, k)];
for(int u = 1; u < 8; u ++ )
{
int x = i - d[u][0], y = j - d[u][1], z = k - d[u][2], t = d[u][3];
s[get(i, j, k)] -= s[get(x, y, z)] * t;
}
if(s[get(i, j, k)] < 0) return true;
}
return false;
}
int main()
{
scanf("%d%d%d%d", &A, &B, &C, &m);
// 生命值读入
for(int i = 1; i <= A; i ++ )
for(int j = 1; j <= B; j ++ )
for(int k = 1; k <= C; k ++ )
scanf("%lld", &s[get(i, j, k)]);
// 求差分数组 b[]
for(int i = 1; i <= A; i ++ )
for(int j = 1; j <= B; j ++ )
for(int k = 1; k <= C; k ++)
for(int u = 0; u < 8; u ++ )
{
int x = i - d[u][0], y = j - d[u][1], z = k - d[u][2], t = d[u][3];
bp[get(i, j, k)] += s[get(x, y, z)] * t;
}
// 读入覆盖范围,攻击伤害
for(int i = 1; i <= m; i ++ )
for(int j = 0; j < 7; j ++ )
scanf("%d", &op[i][j]);
// 二分
int l = 1, r = m;
while(l < r)
{
int mid = l + r >> 1;
if(check(mid)) r = mid;
else l = mid + 1;
}
printf("%d\n", r);
return 0;
}
|
8 全球变暖
题目
你有一张某海域 N×N 像素的照片,".“表示海洋、"#“表示陆地,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
.......
.##....
.##....
....##.
..####.
...###.
.......
|
其中"上下左右"四个方向上连在一起的一片陆地组成一座岛屿。例如上图就有 2 座岛屿。
由于全球变暖导致了海面上升,科学家预测未来几十年,岛屿边缘一个像素的范围会被海水淹没。具体来说如果一块陆地像素与海洋相邻(上下左右四个相邻像素中有海洋),它就会被淹没。
请你计算:依照科学家的预测,照片中有多少岛屿会被完全淹没。
输入描述
第一行包含一个整数 N (1≤N≤1000)。
以下 N 行 N 列代表一张海域照片。
照片保证第 1 行、第 1 列、第 N 行、第 N 列的像素都是海洋。
输出描述
输出一个整数表示答案。
解析
🟠 【dfs】 每次都遍历一整块岛屿,并标记其是否能幸存。 注意有的岛屿可能被淹为两块,因此不能只看最后剩了多少块岛屿。 被淹没岛屿数 = 原始岛屿数 - 幸存岛屿数
🟡 读取海域时为了避免读入空行, 用 %s 而不是 %c
🟢 注意代码中类型,因为 char 写成了 int 而找了好久错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#include <bits/stdc++.h>
using namespace std;
int n,flag=0,sum=0,cnt=0;
char a[1005][1005]; // 记录原始海域,注意是 char 类型!!!
int d[1005][1005]; // 标记每块地是否是被访问过的陆地
void dfs(int x,int y){
// 标记这块陆地已经访问过
d[x][y]=1;
// 如果这块陆地不会被淹没,标记为幸存岛屿
if(a[x-1][y]=='#' && a[x+1][y]=='#' && a[x][y-1]=='#' && a[x][y+1]=='#')
flag=1;
// 遍历这块岛屿的其他陆地
if(d[x-1][y]==0 && a[x-1][y]=='#') dfs(x-1,y);
if(d[x+1][y]==0 && a[x+1][y]=='#') dfs(x+1,y);
if(d[x][y-1]==0 && a[x][y-1]=='#') dfs(x,y-1);
if(d[x][y+1]==0 && a[x][y+1]=='#') dfs(x,y+1);
}
int main(){
cin>>n;
for(int i=0;i<n;i++) // 输入岛屿
scanf("%s",a[i]); // 为了避免读入空行,用 %s 而不是 %c
memset(d,0,sizeof(d));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(a[i][j]=='#' && d[i][j]==0){
dfs(i,j);
sum++; // 记录原始岛屿的数量
if(flag){
cnt++; // 记录幸存岛屿的数量
flag=0; // 标记归零
}
}
}
}
cout<<sum-cnt; // 淹没岛屿 = 原始岛屿 - 幸存岛屿
return 0;
}
|
9 倍数问题
题目
众所周知,小葱同学擅长计算,尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况,当有很多个数之后就会比较苦恼。现在小葱给了你 n 个数,希望你从这 n 个数中找到三个数,使得这三个数的和是 k 的倍数,且这个和最大。数据保证一定有解。
输入描述
第一行包括 2 个正整数 n, k 。
第二行 n 个正整数,代表给定的 n 个数。
其中,$1≤n≤10^5, 1≤k≤10^3$ ,给定的 n 个数均不超过 $10^3$ 。
输出描述
输出一行一个整数代表所求的和。
解析
🟣 因为要求最大数,所以先排序再从后往前遍历,暴力居然过了。。。(或许是数据集太水了,有空更新普适方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#include <bits/stdc++.h>
using namespace std;
int main(){
// 输入数据
int n,k,a[100005],max=0;
cin>>n>>k;
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
// 给 n 个数排序
sort(a,a+n);
// 从大到小遍历
// 注意 i 最大,三个数之和不一定最大!!!
for(int i=n-1;i>=0;i--){
if(a[i]+a[i-1]+a[i-2]<max) break;
for(int j=i-1;j>=0 && a[i]+a[j]+a[j]>k;j--){
if(a[i]+a[j]+a[j-1]<max) break;
for(int r=j-1;r>=0 && a[i]+a[j]+a[r]>=k;r--){
if(a[i]+a[j]+a[r]<max) break;
else if((a[i]+a[j]+a[r])%k==0)
max=a[i]+a[j]+a[r];
}
}
}
cout<<max;
return 0;
}
|
10 付账问题