技巧:手算
- 应用场合:填空题
- 手算的目的:减少做题时间,省下时间做编程题。
手段: - 不编码,或者只做部分编码
- 用推理获得答案
- 用软件工具帮助计算
方法: - 巧用编辑器
- 心算手数
- 巧用 Excel
- 巧用 Python
例题
1.门牌制作
0门牌制作 - 蓝桥云课 (lanqiao.cn)
问题描述:
从 1 到 2020 的所有数字中,共有多少个 2?
- 先编码连续打印出 1∼2020 这 2020 个数字
- 然后粘贴到任何一个编辑器中
- 选查询或替换功能,查找或替换字符 “2”,共 624 次,就是答案。
简单直接,不用思考
除去for循环条件里的两个2,总共有624个2
2. 迷宫
0迷宫 - 蓝桥云课 (lanqiao.cn)
问题描述:
给出一个迷宫,问迷宫内的人有多少能走出来。迷宫如图所示:每个位置上有一个人,共 100 人。每个位置有指示牌,L 表示向左走,R 表示向右走,U 表示向上走,D 表示向下走。
U D D L U U L R U L
U U R L L L R R R U
R R U U R L D L R D
R U D D D D U U U U
U R U D L L R R U U
D U R L R L D L R L
U L L U R L L R D U
R D L U L L R D D D
U U D D U D U D L L
U L R D L U U R R R
- 正解:DFS 搜索,编码 10 分钟。
- 技巧:直接用手画图标记 3-5 分钟。
共31个
3. 星期一
1.星期一 - 蓝桥云课 (lanqiao.cn)
问题描述:
整个 20 世纪(1901年1月1日至 2000年12月31日之间),一共有多少个星期一?
思路:
用Excel,在一个格子里输入日期1901年1月1日,另一个格子输入2000年12月31日,然后两个格子相减得36524 天,除以77得5217.7周。
再看1901年11月11日是星期几。
用Excel点1901年1月1日这一格的“设置单元格式-数字-日期-星期三”,点击“确定”,得“星期二”,即1901年1月1日是星期二,36524是5217周多几天,最后几天没有星期一,说明答案就是5217。
也可以直接利用 Excel“单元格格式”对话框得出2000年12月31日刚好是星期天,从星期二至星期天之间没有星期一。
巧用 Python
填空题遇到字符、大数字、日期问题,Python 是首选。
•即使参加 C/C++、Java 组比赛,也要学一些 Python,以方便手算,或用来做对比测试。
•这几种语言的编译器,在比赛机器上都有。
•写 Python 代码既简单又快,代码长度一般比 C/C++、Java 短很多。例如 30 行的 C++代码,用 Python 写只需要 20 行。
4. 星期一
1.星期一 - 蓝桥云课 (lanqiao.cn)
问题描述:
整个 20 世纪(1901 年 1 月 1 日至 2000 年 12 月 31 日之间),一共有多少个星期一?
直接用 Python datetime 库求解,第 4 行可以输出某个日期是星期几。
from datetime import*
# 定义两个日期对象,dt1表示1901年1月1日,dt2表示2000年12月31日
dt1=datetime(1901,1,1)
dt2=datetime(2000,12,31)
# 输出dt1对应的星期几(周一为0,周二为1,以此类推)
print(dt1.weekday())
# 周一为0,周二为1...
# 计算两个日期之间的天数差,并以整数除以7,得到两个日期之间相差的周数
td=dt2-dt1
print(td.days//7)
相对应的使用 C++同样可以完成,但是编码复杂:
#include <iostream>
using namespace std;
int res; //用于存储总天数的变量
//判断是否为闰年的函数
bool is_r(int n){
if((n % 4 == 0 && n % 100 != 0) || n % 400 == 0)
return true;
return false;
}
int main(){
//循环遍历从1901年到2000年的每一年
for(int i = 1901;i <= 2000;i ++)
// 如果是闰年,增加366天,否则增加365天
if(is_r(i))
res += 366;
else
res += 365;
//将总天数除以7,得到整数部分,表示从1901年到2000年之间的完整周数
int x = res / 7;
//输出结果
cout << x << endl;
return 0;
}
5. 乘积尾零
0乘积尾零 - 蓝桥云课 (lanqiao.cn)
【问题描述】
给出100个整数(这里省略题目给的100个数),问它们乘积的末尾有多少个零。
最简单题解:
- 直接连乘:几千位的大数
- 然后统计末尾的00
但是 C++ 装不下这么大的数字,所以要进行处理:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int cnt2=0,cnt5=0; // 用于统计2和5的因子个数
// 嵌套循环,处理一个10x10的矩阵
for (int i=1;i<=10;i++)
{
for (int j=1;j<=10;j++)
{
int x;
cin>>x; // 从输入中读取一个整数
// 处理2的因子,统计其个数
while (x%2==0)
cnt2++,x/=2;
// 处理5的因子,统计其个数
while (x%5==0)
cnt5++,x/=5;
}
}
// 输出2和5的因子个数中的较小值
cout<<min(cnt2,cnt5)<<'\n';
return 0;
}
思维题
- 不需要涉及某种算法的题目。
- 只要学过编程语言,就能够解答。
- 主要考核学生的思维、逻辑和编码能力,强调脑筋急转弯的解决方式。
- 这类题目包括模拟题、构造题、思维题以及找规律题,统称为“思维题(杂题)”。
- 每年蓝桥杯都会设置这类题目,而且可能有多道,是考试中的重要得分点。
- 杂题涵盖了各种难度,有些可能相对简单,而另一些可能相对较难。
6. 付账问题
0付账问题 - 蓝桥云课 (lanqiao.cn)
【题目描述】
现在有n个人出去吃饭,他们总共消费了S元。其中第i个人带了ai元。幸运的是,所有人带的钱的总数是足够付账的,但现在问题来了:每个人分别要出多少钱呢?
为了公平起见,我们希望在总付钱量恰好为S的前提下,最后每个人付的钱的标准差最小。这里我们约定,每个人支付的钱数可以是任意非负实数,即可以不是1分钱的整数倍。你需要输出最小的标准差是多少。
标准差的介绍:标准差是多个数与它们平均数差值的平方平均数,一般用于刻画这些数之间的"偏差有多大"。
解决思路:
如果每个人携带的钱足够多,每个人平均支付相同的金额,
然而,总会有人的钱不够,这时我们考虑两种情况:
(1)第i个人携带的钱不足以达到平均数avg,那么他只能支付他所携带的全部钱ai。
(2)第i个人携带的钱超过平均数avg,那么他可以支付多一些。
解决步骤:
(1)对ai 进行从小到大的排序;
(2)前一部分人的钱不足以支付平均数,因此他们每个人支付所有携带的钱;
(3)从总支付数中减去前一部分人支付的钱,得到剩余金额′S′,以及后一部分人的平均支付数avg′。
(4)后一部分人携带的钱较多,他们可以支付多一些。这部分人又可以分为两类:
- (i)相对富裕但仍然不足以支付avg′ 的人,他们需要支付所有携带的钱;
- (ii)非常富裕的人,无论如何摊分,他们都有余额。
由于前面一部分人不足以支付avg,因此后面足够支付avg′的人不能只支付avg。相反,他们应该尽可能地每个人支付相同的金额。
因为有人支付不足,总有人支付过多,由于是标准差(方差的平方根),因此每个人支付的金额差距越小越好。
#include <bits/stdc++.h>
using namespace std;
const int M = 5e5;
long long a[M];
int main(){
int n;
long long s;
scanf("%d %lld",&n,&s);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+n+1);
// 对数组a进行从小到大的排序
double avg = 1.0*s/n;
// 计算平均值
double sum = 0.0;
for(int i=1;i<=n;i++){
if(a[i]*(n+1-i) < s){
//需要把钱全拿出的人:
//(1)钱不够平均数的,(2)钱够平均数,但也不是很多的 sum += (a[i]-avg)*(a[i]-avg);
s -= a[i];
//更新剩余钱数
}
else{
//不用把钱全拿出的人:非常有钱,不管怎么平均都够
double cur_avg = 1.0*s/(n+1-i);
//更新平均出钱数
sum += (cur_avg-avg)*(cur_avg-avg)*(n+1-i);
break;
}
}
printf("%.4lf",sqrt(sum/n));
// 输出平均值的标准差,保留四位小数
return 0;
}