目录
数A:
*问题描述*
以下是一个 25 行 25 列的字母矩阵,全部由字母 A 和 B 组成。
AAAAAAABABBAABABABAAAAAAA
ABBBBBABBAABBBBBABABBBBBA
ABAAABABBBABAABBBBABAAABA
ABAAABABBBBBAABAABABAAABA
ABAAABABBABABBABABABAAABA
ABBBBBABBBABAABBBBABBBBBA
AAAAAAABABABABABABAAAAAAA
BBBBBBBBABAABABBBBBBBBBBB
AABAABABBAAABBAAABABBBBBA
ABBABABBBABBAAAABBBBAAAAB
BBBBAAABABAABABAABBBAABBA
BBAABABABAAAABBBAABBAAAAA
ABABBBABAABAABABABABBBBBA
AAAABBBBBABBBBAAABBBABBAB
AABAABAAABAAABAABABABAAAA
ABBBBBBBBABABBBBABAABBABA
ABBBAAABAAABBBAAAAAAABAAB
BBBBBBBBABBAAABAABBBABBAB
AAAAAAABBAAABBBBABABAABBA
ABBBBBABBAABABAAABBBABBAA
ABAAABABABBBAAAAAAAAAABAA
ABAAABABABABBBABBAABBABAA
ABAAABABBABBABABAABAABAAA
ABBBBBABABBBBBABBAAAABAAA
AAAAAAABAABBBAABABABBABBA
请问在这个矩阵中有多少个字母A?
*答案提交*
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
答案:318
回顾反思:
记忆中答案应该是对的。
最2数字:
*问题描述*
如果一个整数的某个数位包含 2 ,则称这个数为一个“最2数字”。例如:102、2021 都是最2数字。
请问在 1(含) 到 2021(含) 中,有多少个最2数字。
*答案提交*
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
答案:564
回顾反思:
我写的答案一定是错了。
错因:题目理解错误(可能是图快、不细心等原因),犯了最常见的错误。当时我以为是计算从1到2021每个数中出现2的总次数,但是真正题意是问只要这个数包括2,就算是最2数字,求有多少个最2数字!!!
数字操作:
*问题描述*
有一个整数 A=2021,每一次,可以将这个数加 1 、减 1 或除以 2,其中除以 2 必须在数是偶数的时候才允许。
例如,2021 经过一次操作可以变成 2020、2022。
再如,2022 经过一次操作可以变成 2021、2023 或 1011。
请问,2021 最少经过多少次操作可以变成 1。
*答案提交*
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
答案:14
回顾反思:
题目类型:宽搜
本以为我搞的是贪心,只要是奇数我就减1,偶数就除以2,想着这一定是最快的。但是在除以2的领域内,最快还得是2的幂次!
下面是寻求答案的代码:
#include<bits/stdc++.h>
using namespace std;
bool st[2100];
int prevc[2100];
int d[2100];
int main()
{
queue<int> q;
q.push(2021);
d[2021] = 0;
st[2021] = true;
while (q.size())
{
auto t = q.front();
q.pop();
if(t == 1) break;
if(!st[t - 1])
{
q.push(t - 1);
d[t - 1] = d[t] + 1;
st[t - 1] = true;
prevc[t - 1] = t;
}
if(!st[t + 1])
{
q.push(t + 1);
d[t + 1] = d[t] + 1;
st[t + 1] = true;
prevc[t + 1] = t;
}
if((t & 1) == 0 && !st[t / 2])
{
q.push(t / 2);
d[t / 2] = d[t] + 1;
st[t / 2] = true;
prevc[t / 2] = t;
}
}
cout << "答案:" << d[1] << endl;
int idx = 1;
cout << 1 << endl;
while (prevc[idx] != 2021)
{
cout << prevc[idx] << endl;
idx = prevc[idx];
}
cout << prevc[idx] << endl;
return 0;
}
/*
运行效果:
答案:14
1
2
4
8
16
32
64
63
126
252
504
505
1010
2020
2021
*/
显然到了63后,是需要加1的,而我忽视了加1的存在。
螺旋矩阵:
*问题描述*
对于一个 n 行 m 列的表格,我们可以使用螺旋的方式给表格依次填上正整数,我们称填好的表格为一个螺旋矩阵。
例如,一个 4 行 5 列的螺旋矩阵如下:
1 2 3 4 5
14 15 16 17 6
13 20 19 18 7
12 11 10 9 8
请问,一个 30 行 30 列的螺旋矩阵,第 20 行第 20 列的值是多少?
*答案提交*
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
答案:819
回顾反思:
当时题解老师讲的时候说还不如手算(但毕竟是讲解视频,老师是不会带着我们手算的!),是啊,手算也得比我写出来要快很多呀!
虽然我费了好大劲写出来,但还是写出代码并得出最终结果了!
最大深度:
*问题描述*
一棵二叉树有2021个结点。该树满足任意结点的左子树结点个数和右子树的结点个数之差最多为1。
定义根结点的深度为0,子结点的深度比父结点深度多1。
请问,树中深度最大的结点的深度最大可能是多少?
*答案提交*
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
答案:10
回顾反思:
得出了正确答案。本题可以直接递归答案来做,即f(n) = f(n / 2) + 1。
#include<bits/stdc++.h>
using namespace std;
int f(int x)
{
if(x == 1) return 0;
else return f(x / 2) + 1;
}
int main()
{
int x = 2021;
cout << f(2021) << endl;
return 0;
}
和尚挑水:
*问题描述*
一个和尚要挑水,每次最多能挑 a 千克,水缸最多能装 t 千克,开始时水缸为空。
请问这个和尚最少要挑多少次可以将水缸装满?
*输入格式*
输入一行包含两个整数 a, t,用一个空格分隔。
*输出格式*
输出一行包含一个整数,表示答案。
*样例输入*
20 2021
*样例输出*
102
*评测用例规模与约定*
对于所有评测用例,1 <= a <= 100,1 <= t <= 10000。
回顾反思:
整体难度不大,跟我写的代码差不多。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a,t,ans;
cin >> a >> t;
ans = t / a;
if(t % a != 0) ans++;
cout << ans << endl;
return 0;
}
千分读入:
*问题描述*
在金融领域,通常将金额的百位和千位之间、十万位和百万位之间增加逗号(千分位分隔符),以方便阅读。一般从个位开始,每三位之前增加一个逗号。
例如:1234567890.00 通常写成 1,234,567,890.00。
注意小数点后固定保留 2 位。
给定一个包含千分位分隔符的数值,请读入后输出对应的不含千分位的数值,小数点仍然保留 2 位。
*输入格式*
输入一行包含一个由千分位分隔符的数值,恰好有 2 位小数。
*输出格式*
输出不含千分位分隔符的数值,保留 2 位小数。
*样例输入*
1,234,567,890.00
*样例输出*
1234567890.00
*评测用例规模与约定*
对于所有评测用例,给定的数值整数部分不超过12位。
回顾反思:
只要跳过逗号就行了,难度不大,但题解给的更是简洁,值得借鉴!
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s;
cin >> s;
for(int i = 0;i < s.size();i++)
if(s[i] != ',') cout << s[i];
return 0;
}
插头:
*问题描述*
小蓝有一个插板,形状用一个 n * m 的01矩阵表示,0 表示板面,1 表示插孔。
小蓝还有一个插头,形状用一个 r * c 的01矩阵表示,0 表示没有伸出的部分,1 表示伸出的部分。插头伸出的部分必须插在插孔里面。
为了安全,插头插到面板上不能有任何部分超过插板边界(包括没有伸出的部分)。
插头和插板都不能旋转,也不能翻转。请求出插头插入插板的合理位置。
*输入格式*
输入的第一行包含两个整数 n, m。
接下来 n 行,每行一个长度为 m 的01串,表示插板的形状。
接下来一行包含两个整数 r, c。
接下来 r 行,每行一个长度为 c 的01串,表示插头的形状。
*输出格式*
如果插头没办法安全插入插板中,输出“NO”。否则输出两个数 a, b,表示插头的第 1 行第 1 列对应插板的第 a 行第 b 列。如果有多种情况满足要求,输出 a 最小的方案,如果 a 最小的方案有多个,输出在 a 最小的前提下 b 最小的方案。
*样例输入*
3 4
0110
0000
0000
3 3
000
010
000
*样例输出*
NO
*样例说明*
在插头不超出范围的前提下无法插入。
*样例输入*
4 7
1110100
1101111
0001111
0000011
2 3
111
011
*样例输出*
2 4
*评测用例规模与约定*
对于 50% 的评测用例,2 <= n, m, r, c <= 20。
对于所有评测用例,2 <= n, m, r, c <= 100。
回顾反思:
“暴力枚举”
我感觉我但是写的有问题,我没有判断边界,这样的话可能会出现数组越界等细节问题。
下面的代码有很多值得借鉴的地方,如string数组的输入,更为厉害的是封装函数,这样可以避免因代码集中在一起导致的思路混乱等!
#include<iostream>
#include<string>
using namespace std;
string s[100],t[100];
int n,m,r,c;
bool ok(int a,int b)
{
for(int i = 0;i < r;i++)
for(int j = 0;j < c;j++)
if(t[i][j] == '1' && s[a + i][b + j] != '1') return false;
return true;
}
int main()
{
cin >> n >> m;
for(int i = 0;i < n;i++) cin >> s[i];
cin >> r >> c;
for(int i = 0;i < r;i++) cin >> t[i];
for(int a = 0;a <= n - r;a++)
for(int b = 0;b <= m - c;b++)
if(ok(a,b))
{
cout << a + 1 << " " << b + 1 << endl;
return 0;
}
cout << "NO" << endl;
return 0;
}
公约数:
*问题描述*
给定正整数 a, b, c,请问有多少个正整数,是其中至少两个数的约数。
*输入格式*
输入一行包含三个正整数 a, b, c。
*输出格式*
输出一行包含一个整数,表示答案。
*样例输入*
30 70 35
*样例输出*
6
*样例说明*
1、2、5、7、10、35满足条件。
*评测用例规模与约定*
对于 50% 的评测用例,1 <= a, b, c <= 1000000。
对于所有评测用例,a, b, c 不超过 10**12(10的12次方)。
回顾反思:
#include<iostream>
#include<string>
#include<set>
using namespace std;
typedef long long ll;
set<ll> S;
ll gcd(ll a,ll b)
{
return b ? gcd(b,a % b) : a;
}
//a和b的公约数一定都是a和b的最大公约数d的约数,即题目转换为求d的所有约数
void solve(ll a,ll b)
{
ll d = gcd(a,b);//小细节(ll),公约数也有可能是爆int的值
for (int i = 1; i <= d / i; i++)
{
if(d % i == 0)
{
S.insert(i);
if(i != d / i) S.insert(d / i);
}
}
}
int main()
{
ll a,b,c;
cin >> a >> b >> c;
solve(a,b);
solve(b,c);
solve(a,c);
cout << S.size() << endl;
return 0;
}
汉诺塔:
*问题描述*
小蓝很喜欢玩汉诺塔游戏。
游戏中有三根柱子,开始时第一根柱子上有 n 个圆盘,从上到下圆盘的大小依次为 1 到 n。
每次,可以将一个盘子从一根柱子上移动到另一根柱子上,这个盘子必须是柱子最上方的盘子,而且移到的柱子上的盘子必须比这个盘子大。
小蓝的目标是将所有的盘子移动到第三根柱子上。
汉诺塔是个经典问题,当盘子数量为 n 时,最少需要移动 2n-1 步,其中 2n 表示 2 的 n 次方。
小蓝已经玩了一会儿(不一定按最优方案玩),他想知道,对于他目前的局面,最少还需要多少步可以到达目标。
*输入格式*
输入的第一行包含三个非负整数 a, b, c,分别表示目前每根柱子上的盘子数。在本题中,n=a+b+c。
第二行包含 a 个整数,相邻的整数之间使用一个空格分隔,表示第一根柱子上的盘子,盘子按从上到下(从小到大)的顺序给出。
第三行包含 b 个整数,相邻的整数之间使用一个空格分隔,表示第二根柱子上的盘子,盘子按从上到下(从小到大)的顺序给出。
第四行包含 c 个整数,相邻的整数之间使用一个空格分隔,表示第三根柱子上的盘子,盘子按从上到下(从小到大)的顺序给出。
*输出格式*
输出一行包含一个整数,表示答案。
*样例输入*
1 2 3
1
2 3
4 5 6
*样例输出*
7
*评测用例规模与约定*
对于 30% 的评测用例,2 <= n <= 5。
对于所有评测用例,2 <= n <= 60。
回顾反思:
这题我是一定也不会呀,普通的递归我也写不出来。。。题解见代码注释:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100;
int d[4][N],p[N];
//d[][]记录每个柱子上的数字;p[]记录每个数字在哪个柱子上
ll f(int n,int k)
{
if(n == 0) return 0;//没有盘子了,返回0
if(p[n] == k) return f(n - 1,k);
return f(n - 1,6 - k - p[n]) + (1ll << (n - 1));
}
int main()
{
int a,b,c;
cin >> a >> b >> c;
int n = a + b + c;
for(int i = 1;i <= a;i++)
{
cin >> d[1][i];
p[d[1][i]] = 1;
}
for(int i = 1;i <= b;i++)
{
cin >> d[2][i];
p[d[2][i]] = 2;
}
for(int i = 1;i <= c;i++)
{
cin >> d[3][i];
p[d[3][i]] = 3;
}
cout << f(n,3) << endl;//将n个盘子放到第3个柱子上
return 0;
}
/*
分析:
1、如果第n个盘子在第3个柱子上,则不消耗
2、如果第n个盘子不在的话:
(1) 需要先将n - 1个盘子放到既不在n所在的盘子上又不在目标k所在的盘子上的位置
(2) 再将第n个盘子放到目标位置,加1
(3) 将剩余排好的n - 1个盘子由公式2**n - 1计算出放到k盘子上的个数
那么由(1)(2)(3)累加得,结果为f(n - 1,6 - p[n] - k) + (1ll << (n - 1));
提示:一共3个柱子,顺序为1,2,3故总数为6,去掉其中一个柱子再去另一个柱子的编号,即为最后需要放的柱子编号。即6 - p[n] - k。
*/