🍦🍦🍦今天我们继续来看第一章的后半部分:考试最佳策略、预处理与打表技巧、对数器技巧等内容。加油!fighting!( •̀ ω •́ )✧
目录
🧊🧊🧊1.4 考试最佳策略
提前准备
1、算法模板一定要提前准备好,不管是单独打印还是记录在书上。
2、算法模板一定要验证它的正确性,在验证的过程中也知道了该如何使用。
3、手机调成静音模式,最好再开一个飞行模式,不要上交以备不时之需。
注意,有的学校要求不允许带任何纸质资料,这种情况下只能大家自己多练习多记忆了!
开考前
1、验证鼠标键盘是否可用,如果不可用及时向老师反应,更换电脑。
2、验证 IDE(如:codeblocks)是否可用,如果不可用及时向老师反应,更换电脑。
3、可以提前将多道题的文件都创建好,一道题卡住了就写下一道。
考试中
1、机试中的题目难度不是从简单到难,难度是随机的,所以刚开始一定要将所有题目都看一遍。
2、找到你认为最简的那道题开始做,记住,一定要从最简单的题目开始做。
3、考试过程中要注意看排行榜,通过人数最多的题目一般都是最简单的题目。
4、当无法通过一个题的时候,先看看有没有其他能做的题,如果也没有其他题能做了,这个时候你就可以使用很多特殊的办法,首先,你一定要相信,机试的数据一定不够强。一般情况下,机试的判题数据都会找学生帮忙生成,往往强度就不会很高。
5、不要被题目的数据范围吓到,有可能后台都是小数据,没有更好的解法的时候一定要试试暴力。
6、我们往往被卡都是因为算法不够优秀导致超时,一方面我们可以强行优化输入输出加速来看看能不能水过去。另一方面可以采用小数据暴力,大数据随机的思想来解决问题。
小数据暴力、大数据随机
原理:由于大数据出多组容易导致判题很慢,所以往往不会有很多组。另外对于特殊的数据可能需要手动构造,大数据构造起来麻烦,还要自己构思生成数据的代码。所以一般都是用小数据来验证算法正确性,再加上两组大数组验证算法复杂度。
比如说背包问题:
我们背包问题一般使用动态规划来解,但是你不会怎么办?
那么我们就可以小数据暴力搜索,大数据直接贪心。对于数据不够强的题就能水过去。
🧊🧊🧊1.5 预处理与打表技巧
预处理
预处理是指将答案提前处理好然后再进行查询的方法。
什么时候会用到预处理:查询量特别大的时候。
例题
我们要查询斐波那契数列的第 n 项,n(n < 10000)。并且我们要查询 10 万次。
错误的超时解法:
#include<bits/stdc++.h>
using namespace std;
int f[10005];
int main(){
int t;
scanf("%d", &t);//查询次数
while (t--) {
int n;
scanf("%d", &n);//查询第 k 项
f[1] = 1;
f[2] = 1;
for (int i = 3; i <= n; i++) {
f[i] = f[i-1] + f[i-2];
}
printf("%d\n", f[n]);
}
return 0;
}
超时分析:每一次查询,我们都递推了一遍斐波那契数列,如果每一次查询的都是最后一项。那么最坏情况就是:100000*10000,必然是会超时的。
正确的预处理解法:
#include<bits/stdc++.h>
using namespace std;
int f[10005];
int main(){
f[1] = 1;
f[2] = 1;
for (int i = 3; i <= 10000; i++) {
f[i] = f[i-1] + f[i-2];
}
int t;
scanf("%d", &t);//查询次数
while (t--) {
int n;
scanf("%d", &n);//查询第 k 项
printf("%d\n", f[n]);
}
return 0;
}
可以发现两段代码惊人的相似,有什么区别呢?
区别在于下面的代码只会递推一遍斐波那契数列,然后将所有的答案都存储于 f 数组中。
一般打表技巧
打表是指我们提前使用暴力的方法,将答案记录下来写到纸上或代码中,然后再根据题目的实际需求去直接输出提前记录好的答案。
例题
求一个数 x 的 100000000 次方模 2333 的值是多少。x 的范围是(1<= x <=10)
解析:这个时候我们如果不会二分快速幂的话,可以直接用一个暴力的代码将 1 到 10 的答案分别求出来,可能要等上几分钟,然后直接判断输入的值对应输出结果即可。
打表找规律
在一些可能存在规律的问题中,我们可以通过暴力打表求出前几十项的值,发现其中的规律,从而帮助我们解出该题。
例题
输入一个整数 a(a<10^9),b 可以取任意值,求 a%b 的可能产生多少种不同的结果。
解析:乍一看,我们一脸懵逼。这个时候你只要去打表分析,首先 b 大于 a 就重复了,那么我们只需要对于任意一个 a,去枚举 b 的值,看 a%b 会产生多少种不同的结果即可。通过打表分析,你会发现:当 a = 1 时,结果 ans = 1,当 a 为偶数时,ans = a / 2 + 1,当 a 为奇数时,ans = a / 2 + 2。
🥥练习题目:
DreamJudge 1488 数字填充
![](https://i-blog.csdnimg.cn/direct/9ee2a4fce5bc4d8887cc53fe4cc6f0ce.png)
![](https://i-blog.csdnimg.cn/direct/008ebdf557834d93bb2877f46797b956.png)
#include<bits/stdc++.h>
using namespace std;
int main()
{
string a[10][5];
a[0][0]="111";
a[0][1]="101";
a[0][2]="101";
a[0][3]="101";
a[0][4]="111";
a[1][0]="001";
a[1][1]="001";
a[1][2]="001";
a[1][3]="001";
a[1][4]="001";
a[2][0]="111";
a[2][1]="001";
a[2][2]="111";
a[2][3]="100";
a[2][4]="111";
a[3][0]="111";
a[3][1]="001";
a[3][2]="111";
a[3][3]="001";
a[3][4]="111";
a[4][0]="101";
a[4][1]="101";
a[4][2]="111";
a[4][3]="001";
a[4][4]="001";
a[5][0]="111";
a[5][1]="100";
a[5][2]="111";
a[5][3]="001";
a[5][4]="111";
a[6][0]="111";
a[6][1]="100";
a[6][2]="111";
a[6][3]="101";
a[6][4]="111";
a[7][0]="111";
a[7][1]="001";
a[7][2]="001";
a[7][3]="001";
a[7][4]="001";
a[8][0]="111";
a[8][1]="101";
a[8][2]="111";
a[8][3]="101";
a[8][4]="111";
a[9][0]="111";
a[9][1]="101";
a[9][2]="111";
a[9][3]="001";
a[9][4]="111";
string s;
cin>>s;
int len=s.size();
int b[100];
for(int i=0;i<len;i++) b[i]=s[i]-'0';
for(int i=0;i<5;i++)
{
for(int j=0;j<len;j++) cout<<a[b[j]][i];
cout<<endl;
}
return 0;
}
🧊🧊🧊1.6 对数器技巧
这一节主要是为了解决下述情况的问题:题目做半天还是错,看起来和别人的代码也差不多,就是不知道错在哪了,而且反馈错误数据也是成千上万行,根本没法去对比……
使用对数器进行对拍,可以快速的找到的你的代码错误所在。
简单说,就是将你的代码和正确的代码放在一起,然后随机生成一些符合题目的要求的数据,然后比较你的代码的输出结果和正确代码的输出结果是否一致,从而来验证你的代码的正确性。
当然,随机的数据越多,正确性也就越高。
我们举个排序的例子来看怎么用对数器:
我自己写了一个排序的算法,但是我不知道我写的这个排序算法到底有没有问题,但是我拿到别人的正确的排序的算法代码,我如何比较呢?
我的代码:
for (int i = 1; i <= n; i++)
for (int j = 1; j < n; j++)
if (b[j] > b[j+1])
swap(b[j], b[j+1]);
正确的:
sort(c+1, c+n+1);
对数器使用模板:
#include <bits/stdc++.h>
using namespace std;
struct node {
int a[105];//随机的数
int b[105];//我的方法排序后的数
int c[105];//正确的方法排序后的数
int n;
// 按照题意随机一些输入数据
void Rand() {
n = rand()%100 + 1;
for (int i = 1; i <= n; i++)
a[i] = rand()%10000;
}
// 使用我的解法得到的答案
void My_method() {
for (int i = 1; i <= n; i++)
b[i] = a[i];
for (int i = 1; i <= n; i++)
for (int j = 1; j < n; j++)
if (b[j] > b[j+1])
swap(b[j], b[j+1]);
}
// 使用其他正确的解法得到的答案
void Right_method() {
for (int i = 1; i <= n; i++)
c[i] = a[i];
sort(c+1, c+n+1);
}
// 比较我的答案和正确答案是否一致
// 如果不一致输出测试数据然后分析
int Check() {
for (int i = 1; i <= n; i++) {
if (b[i] != c[i]) {
printf("my code is error!\n");
printf("the test data:\n");
for (int j = 1; j <= n; j++) {
printf("%d ", a[j]);
}
printf("\n");
return 1;
}
}
return 0;
}
};
int main() {
srand(time(NULL));//将时间作为随机种子
int t = 100;//样本大小
while (t--) {
node code;
code.Rand();
code.My_method();
code.Right_method();
if (code.Check()) return 0;
}
printf("my code is right!\n");
}
代码分析:首先随机 100 组输入数据,然后使用自己的算法去跑出结果,然后使用正确的算法去跑出结果,最后比较两个结果是否一致,如果不一致就输出是哪一组数据导致的结果不一致,最后分析自己的算法问题所在。
创作不易,点个赞吧~点赞收藏不迷路,感兴趣的宝子们欢迎关注该专栏~
勤奋努力的宝子们,学习辛苦了!宝子们可以收藏起来慢慢学哦~🌷🌷🌷休息下,我们下部分再见👋( •̀ ω •́ )✧~