目录


🎬 云泽Q :个人主页
🔥 专栏传送入口 : 《C语言》《数据结构》《C++》《Linux》《蓝桥杯系列》
⛺️遇见安然遇见你,不负代码不负卿~
前言
大家好啊,我是云泽Q,欢迎阅读我的文章,一名热爱计算机技术的在校大学生,喜欢在课余时间做一些计算机技术的总结性文章,希望我的文章能为你解答困惑~
一、好数
好数

考察内容:模拟
解法 :
对于一个数x,拆分数的每一位,x不断模10,先提取最低位,再x除以10把最低位删掉,在提取的过程中可以定义一个变量i = 1来记录当前这一位是第几位,每次x % 10就看看是否与该变量同奇或同偶,若第一位是奇数,则说明与i = 1同奇,每次执行完x % 10, x / 10,让i++继续对比下一位
cpp
#include<iostream>
using namespace std;
bool check(int x)
{
int i = 1;
while(x)
{
//对应位奇偶性相等
if(((x % 10) % 2 != (i % 2))) return false;
x /= 10;
i++;
}
return true;
}
int main()
{
int n; cin >> n;
int ret = 0;
for(int i = 1; i <= n; i++)
{
if(check(i))
ret++;
}
cout << ret << endl;
return 0;
}
二、R 格式
R格式


考察内容:高精度
这道题建议将下面的文字配合上面的图来看,细节太多,我就没有把文字内容备注到图里:
具体操作就是将浮点数d拆分每一位存入一个整数数组,然后依次乘n个2即可,不过这个过程中还有一些细节问题,这个浮点数还存在小数点,这个小数点需要特殊处理
因为这个浮点数的数据范围太大,读取浮点数用字符串来读,这里的小数点也会占一位
在将浮点数放入数组中有人可能会考虑到这种情况,1.25 × 2 × 2的过程中,每乘一次2会有小数点后的位数变小的情况,原来小数点后有两位,计算完之后得到5一位也没有了,这种情况并不用担心,可以先将这个1.25看作125,乘两次2之后就是500,这时候计算完再看之前1.25的小数点后有两位,此时就在最终结果倒数第二位这里加上一个小数点即可,和前面的计算结果是完全一样的,因此在用数组存浮点数的时候,并不关心小数点在哪里,只关心小数点后有多少位。再用数组存浮点数的时候直接将除小数点以外的数逆序存进去,用变量p标记小数点后有多少位,当用数组计算出最终结果的时候,例如这里p = 2,在第2位和第3位(数组从第一位开始计数)之间加上一个小数点即可
此时浮点数存入数组的时候还有一个细节问题,由于不存小数点,这里字符串下标与数组下标直接找对应关系是有问题的,比如字符串下标为5的位置对应数组下标为0的位置,下标值之和为5没有问题。字符串下标为4的位置对应数组下标为1的位置,下标值之和为5没有问题。字符串下标为2的位置对应数组下标为2的位置,下标值之和为4就存在问题了,所以逆序存储的时候还有一个小操作,先定义一个变量 i 从前往后遍历字符串数组,再定义一个变量 t 指向整型数组的最后一个位置,这个最后一个位置是可以通过计算得到的(先计算字符串的长度记为len = d.size() = 6,由于小数点不存,直接 -1 长度变为5,实际的数的个数是5个,这样整型数组最后一个数的下标就是t = len - 1,也就是t = 5 - 1 = 4),当i从下标0开始在字符串浮点数遍历的时候,当i每指向一个数填入到整型数组当中i++后,t也从最后一个位置开始向前减,比如i指向下标为0的位置2加入到t指向的下标为4的位置,i++,t- -。只要i指向的是一个数,比如现在指向3,将3填入后,重复前面的操作

直到i指向小数点位置(下标为3的位置,不是一个数了),此时只i++,t不- -,此时遍历到一个5的时候,再把这个5扔到t位置,然后i++,t- -


当遍历到最后一个数6的时候,将6放入t指向的位置,i++,t- -


此时就特殊处理的小数点的位置,就是多定义一个变量t。此时将所有的数存入整型数组中的时候,就变为了一个高精度 × 低精度的问题,在乘完n个2之后,由于p = 2,此时p指向下标为2对应4的位置,该位置的前一个位置5就是小数点后的最近一位,p位置指的是小数点前的最近一位4,若小数点后的最后一位大于5的话,p指向的位置再向前进一位即可

若p指向的位置是9且p指向位置的前一位 >= 5,此时9 + 1之后就要继续向前(3)进一位,p指向位置的后面位置也有可能有这种情况,所以也要处理这种细节情况

输出结果的时候就要从len - 1这里一直逆序输出到p,后面就不用管了,这里就是高精度浮点数 × 低精度的过程

再实现代码之前,先掏出计算器看这道题要开多大的数组

21000是300多位,d最多是1024位

结果最多是3.0×105位,这里数组大小我直接开1e6 + 10,绝对够用
cpp
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int n;
string d;
int a[N], len, p;
void mul()
{
//标记进位
int c = 0;
for (int i = 0; i < len; i++)
{
a[i] = a[i] * 2 + c;
c = a[i] / 10;
a[i] %= 10;
}
//最终可能还有一个进位,直接放到前一位
if (c) a[len++] = c;
}
int main()
{
cin >> n >> d;
//len是去除小数点后的数组长度
len = d.size() - 1;
for (int i = 0, t = len - 1; i < d.size(); i++)
{
//若当前位是小数点,特殊标记
//p标记小数点后有多少位
if (d[i] == '.') p = d.size() - i - 1;
//若当前位是数,逆序存入数组
else a[t--] = d[i] - '0';
}
//乘 n 个2
for (int i = 1; i <= n; i++) mul();
//判断四舍五入
if (a[p - 1] >= 5)
{
int c = 1;
//进位若等于0,不用再加
for (int i = p; i < len && c; i++)
{
a[i] = a[i] + c;
c = a[i] / 10;
a[i] %= 10;
}
if (c) a[len++] = c;
}
//输出结果,从最高位输出到p位
for (int i = len - 1; i >= p; i--) cout << a[i];
return 0;
}
三、拔河
拔河



考察内容:枚举 + set
【解法】
可以通过枚举右区间 [l,r] 的和 sum,然后在 [1,l−1] 内的所有区间中找出距离 sum 最近的区间长度。
那么,可以将 [1,l−1] 中的所有区间和信息存入 set 中(因为set这个数据结构是一个有序表),这样就可以在 log 时间内找出距离 sum 最近的区间。但是要注意,有可能比 sum 大,也有可能比 sum 小。
补充一下图中所说把[1, l - 1]里面所有区间和放入set中的详细原理过程 :
当枚举[l, r]这个区间的时候,如果使用两层for循环把左边所有的区间和放到set中,时间开销也是很爆炸的,和暴力枚举的时间开销是一样的,因此要做到在枚举右边区间的时候,快速的把左边这个区间的区间和全部扔到set中,此时就可以根据枚举的特点,假设枚举到[l, r]区间的时候,假设此时左边的区间和已经全部在set中

当枚举完[l, r]区间的时候,此时只需将l指向的位置向后移动一位,此时根据之前l的位置计算出来的左边的区间和依旧可以再用

无非就是新l向后移动一位之后,只添加了以这个旧l为结尾的区间,只要把新添加的这些区间和重新扔到set当中就可以了

并且这个时间复杂度仅需从后往前遍历一遍就可以做到

和把l枚举到新位置之后,再定义一个指针r从此位置向后枚举这个区间的时间开销等同,所以我们就可以在一边枚举右边区间,一边把新产生的区间和放入set中即可,也就可以说这个放入set的过程是不耗时的

cpp
#include<iostream>
#include<set>
using namespace std;
const int N = 1e3 + 10;
typedef long long LL;
LL n;
LL a[N];
set<LL> mp;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
//统计最终最小差距
LL ret = 1e9;
//枚举[l, r]区间
for (int l = 2; l <= n; l++)
{
LL sum = 0;
//把新产生的区间和,放入set中
for (int i = l - 1; i >= 1; i--)
{
sum += a[i];
mp.insert(sum);
}
sum = 0;
//枚举右区间
for (int r = l; r <= n; r++)
{
sum += a[r];
//枚举完右边区间之后
//在左边区间中快速找出离sum最近的区间和
auto it = mp.lower_bound(sum);
//若是可以找到
if (it != mp.end()) ret = min(ret, *it - sum);
//it指向的区间和前面必须还有一个区间和才可以支持--,否则越界
//比如set中的区间和是7,7,9,10,it指向第一个7
if (it != mp.begin())
{
it--;
ret = min(ret, sum - *it);
}
}
}
cout << ret << endl;
return 0;
}
结语
