试题 A: 空间
【问题描述】
小蓝准备用 256MB 的内存空间开一个数组,数组的每个元素都是 32 位
二进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问
256MB 的空间可以存储多少个 32 位二进制整数?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
//一位8字节
#include <iostream>
int main()
{
int res = 256 * 1024 * 1024 / 4;
cout << res << endl;
}
// 67108864
试题 B: 卡片
【问题描述】
小蓝有很多数字卡片,每张卡片上都是数字 0 到 9。
小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个,
就保存起来,卡片就不能用来拼其它数了。
小蓝想知道自己能从 1 拼到多少。
例如,当小蓝有 30 张卡片,其中 0 到 9 各 3 张,则小蓝可以拼出 1 到 10,
但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。
现在小蓝手里有 0 到 9 的卡片各 2021 张,共 20210 张,请问小蓝可以从 1
拼到多少?
提示:建议使用计算机编程解决问题。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
题解:
比赛时我是猜测1是最先用完的,然后去枚举1出现2021次。比赛时是大胆猜测,现在给出证明:
由题目知当第一次出现不够用的数字时就结束,那么肯定是数字越小越先结结束,但是又不出现000这样的数字,且每个数字出现的频率相等所以最先不够用的数字肯定是1。
这种做法并非通法,现在给出通用做法
反向思考,我们可以一直枚举,直到第一次出现某一个数不够用情况
#include <iostream>
#include <cstring>
using namespace std;
int s[10];
bool check(int x)
{
while(x)
{
int t = x % 10;
x /= 10;
if(--s[t] < 0) return false;
}
return true;
}
int main()
{
for(int i = 0; i < 10; i ++ ) s[i] = 2021;
for(int i = 1 ;; i ++ )
{
if(!check(i))
{
cout << i - 1 << endl;
return 0;
}
}
return 0;
}
// 3181
试题 C: 直线
【问题描述】
在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,
那么这些点中任意两点确定的直线是同一条。
给定平面上 2 × 3 个整点 {(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x ∈ Z, y ∈ Z},即横坐标
是 0 到 1 (包含 0 和 1) 之间的整数、纵坐标是 0 到 2 (包含 0 和 2) 之间的整数
的点。这些点一共确定了 11 条不同的直线。
给定平面上 20 × 21 个整点 {(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z},即横
坐标是 0 到 19 (包含 0 和 19) 之间的整数、纵坐标是 0 到 20 (包含 0 和 20) 之
间的整数的点。请问这些点一共确定了多少条不同的直线。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
题解:
比赛时想到了枚举,毕竟时间复杂度不高,202020*20 = 160000。
可是由于平时做的题还是太少,忽略了浮点数不可以用等号判相等,而且也没有考虑到斜率不存在的情况。
- 直接枚举
k,b
- 需要注意在计算机中浮点数是不精确的,毕竟有无限不循环小数存在,所以我们再判断两个浮点数是否相等时,
fabs(d1 - d2) < 1e-8
这样来判断d1 ,d2是否相等 - 最后需要注意的就是斜率不存在时有20条直线。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 200000;
int n;
struct Line{
double k,b;
// 重载 < 进行排序
bool operator< (const Line& t) const
{
if(k != t.k) return k < t.k;
return b < t.b;
}
}l[N];
int main()
{
for(int x1 = 0; x1 < 20; x1 ++ )
for(int y1 = 0; y1 < 21; y1 ++ )
for(int x2 = 0; x2 < 20; x2 ++ )
for(int y2 = 0; y2 < 21; y2 ++ )
if(x1 != x2)//如果是同一点就不进行判断
{
double k = (double)(y2 - y1) / (x2 - x1);
double b = y1 - k * x1;
l[n ++ ] = {
k, b};
}
sort(l, l + n);
int res = 1;
//排序后,只需要判断相邻两个直线是否是同一条直线即可
//考试时用到了set去做,也可以,但是得到的答案就奇奇怪怪o(╥﹏╥)o