蓝桥杯刷题冲刺 | 倒计时7天
作者:指针不指南吗
专栏:蓝桥杯倒计时冲刺🐾最后一周,复习学过的知识,刷题冲刺🐾
文章目录
- 1.高精度除法
- 2.扫地机器人
- 3.数的范围
- 4.A-B 数对
1.高精度除法
-
题目
链接: 794. 高精度除法 - AcWing题库
给定两个非负整数(不含前导 0) A,B,请你计算 A/B 的商和余数。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共两行,第一行输出所求的商,第二行输出所求余数。
数据范围
1≤A的长度≤100000,
1≤B≤10000,
B 一定不为 0输入样例:
7 2
输出样例:
3 1
-
n次之后才 AC
#include<bits/stdc++.h> using namespace std;vector<int> div(vector<int> &A,int &b,int &r) //这里r一定要使用引用 {vector<int> C;r=0;for(int i=A.size()-1;i>=0;i--) //从最高开始除{r=r*10+A[i];C.push_back(r/b); //C 里面存的是 商,不是模,之前不同!!r%=b; //取模!与其他的不同}reverse(C.begin(),C.end()); //反转,与其他运算保持一致while(C.size()>1&&C.back()==0) C.pop_back(); //去掉前导0,除了加不用,其他都是需要的return C; }int main() {string a;int b;cin>>a>>b;vector<int> A;for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0'); //-‘0’ 记得int r=0;auto C=div(A,b,r);for(int i=C.size()-1;i>=0;i--) printf("%d",C[i]);printf("\\n");printf("%d",r); //最后输出 余数return 0; }
-
反思
细节决定成败,我这细节全无 TvT
做的时候,不能只背模板,再想一下原因,为什么这么写,意义是什么!
2.扫地机器人
-
题目
链接: 扫地机器人 - 蓝桥云课 (lanqiao.cn)
小明公司的办公区有一条长长的走廊,由 N 个方格区域组成,如下图所示。
走廊内部署了 K 台扫地机器人,其中第 i 台在第 A i 个方格区域中。已知扫地机器人每分钟可以移动到左右相邻的方格中,并将该区域清扫干净。
请你编写一个程序,计算每台机器人的清扫路线,使得
- 它们最终都返回出发方格,
- 每个方格区域都至少被清扫一遍,
- 从机器人开始行动到最后一台机器人归位花费的时间最少。
注意多台机器人可以同时清扫同一方块区域,它们不会互相影响。
输出最少花费的时间。 在上图所示的例子中,最少花费时间是 6。第一台路线:2-1-2-3-4-3-2,清 扫了 1、2、3、4 号区域。第二台路线 5-6-7-6-5,清扫了 5、6、7。第三台路线 10-9-8-9-10,清扫了 8、9 和 10。
输入描述
第一行包含两个整数 N,K。
接下来 K 行,每行一个整数 A i。
其中,1≤K<N≤10510^5105 ,1≤A i≤N。
输出描述
输出一个整数表示答案。
输入输出样例
示例
输入
10 3 5 2 10
输出
6
-
第一次
我的思路是算出每一个机器人的最短时间取最大值,使用 BFS 不断向两边扩展,直到归位就跳出BFS。但是,没有办法保证每个地方都扫了
-
题解
/* 解题思路: 本题为一道比较明显的二分题目。题目要求最少花费时间。由于每个机器人的工作时间可能不同,那么这些机器人各自的花费时间中的最大值(设为 t )的就是本题要求的答案, 需要做的是使得 t 最小。将最大花费时间(t)最小化,显然需要使用二分求解。假设某个机器人需要清扫 a,b,c,d 四个格子,因为这个机器人清扫完还需要回到最初始的位置,所以无论这个机器人初始位置在什么地方, 其清扫路径的本质都是重复两次 a 到 b,b 到 c,c 到 d 的过程,花费时间为 6,由此,假设某个机器人清扫的格子范围为 l, 那么这个机器人花费的时间为 (l-1)\\times*2。所以只需要对机器人清扫的范围(l)进行二分即可,最后的答案为 t=(l-1)\\times*2。显然当每个机器人清扫的范围大小相同时,花费时间最小。 可以对清扫范围进行二分,然后验证其答案的正确性即可,判断条件是清扫范围可以使得每个格子都能够扫到可以明显的知道,最左边的格子由左边第一台机器人清扫,花费时间是最少的,在此可以采用贪心的思想, 让每台机器人都要优先清扫其左边还未扫的到格子,然后再往右扫,在二分得到的范围下往右扫得越多越好, 这样可以减少右边下一个机器人需要往左扫的范围,增加其往右扫的范围,以此类推,可减少清扫时间。综上,本题采用二分加贪心的思想解答。 */ #include<bits/stdc++.h> using namespace std;int robot[1000005];//机器人位置 int n, k;bool check(int len) {int sweep = 0;//sweep代表清扫到了哪个位置for(int i = 1; i <= k; i++){if(robot[i] - len <= sweep)//如果当前机器人只扫左侧,能够覆盖左侧未清扫的位置,则可进行当前机器人的清扫{if(robot[i] <= sweep)//如果当前机器人已经处于清扫过的位置,则当前机器人只扫右侧区域sweep = robot[i] + len - 1;else//否则从上一个清扫到的位置继续sweep += len;}else//当前机器人只扫左侧,不能覆盖左侧未清扫的位置,当前方案不可行,返回return 0;//cout<<sweep<<endl;}return sweep>=n; //表示当前方案可行 }int main() {cin >> n >> k;for(int i = 1; i <= k; i++){cin >> robot[i];}sort(robot + 1, robot + k + 1);//首先对机器人的位置进行排序int L=0, R=n, M, ans;while(L <= R)//二分清扫范围{M = (L + R) / 2;if(check(M))//如果当前方案可行,则缩小清扫范围,试图寻找更小的方案{R = M - 1;ans = M;}else//如果方案不可行,则扩大清扫范围,寻找可行方案L = M + 1;}cout << (ans - 1) * 2 << endl;//计算并输出答案return 0; }
-
二分模板 复习一下
- 找某个值在区间里面是否存在
int BinSearch(int a[],int low,int high,int k){if(low<=high){ //当前区间存在元素 int mid=(low+high)/2;if(a[mid]==k)return mid; //找到后返回其下标 if(a[mid]<k)return BinSearch(int a[],int low,int mid-1,int k);if(a[mid]>k)return BinSearch(int a[],int mid+1,int high,int k);}else{return -1; //区间不存在元素,返回 -1 }}
- 返回左边 起始值
int l=0,r=n;while(l<r){int mid=l+r>>1;if(check(mid)>=k) r=mid; //起始节点else l=mid+1;}
- 返回右边 后继值
int l=0,r=n-1; while(l<r){ int mid=l+r+1>>1;if(a[mid]<=k) l=mid; //终止节点else r=mid-1;}
-
反思
什么问题可以运用二分搜索算法技巧?
-
首先,你要从题目中抽象出一个自变量
x
,一个关于x
的函数f(x)
,以及一个目标值target
。 -
同时,
x
,f(x)
,target
还要满足以下条件:f(x)
必须是在x
上的单调函数(单调增单调减都可以)题目是让你计算满足约束条件
f(x) == target
时的x
的值。
最重要的就是抽象,这得需要多刷题,才能抽象出来…努力ing
-
3.数的范围
-
题目
链接: 789. 数的范围 - AcWing题库
给定一个按照升序排列的长度为 n 的整数数组,以及 q 个查询。
对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 0 开始计数)。
如果数组中不存在该元素,则返回
-1 -1
。输入格式
第一行包含整数 n 和 q,表示数组长度和询问个数。
第二行包含 n 个整数(均在 1∼10000 范围内),表示完整数组。
接下来 q 行,每行包含一个整数 k,表示一个询问元素。
输出格式
共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回
-1 -1
。数据范围
1≤n≤100000
1≤q≤10000
1≤k≤10000输入样例:
6 3 1 2 2 3 3 4 3 4 5
输出样例:
3 4 5 5 -1 -1
-
第一次 AC 100%
#include<bits/stdc++.h> using namespace std;const int N=1e5+10;int n,m; int a[N];int main() {scanf("%d%d",&n,&m);for(int i=0;i<n;i++)cin>>a[i];while(m--){int k;scanf("%d",&k);//二分查找int l=0,r=n;while(l<r){int mid=l+r>>1;if(a[mid]>=k) r=mid;else l=mid+1;}if(a[l]==k) cout<<l<<' ';else{puts("-1 -1");continue;}l=0,r=n;while(l<r){int mid=l+r+1>>1;if(a[mid]<=k) l=mid;else r=mid-1;}if(a[l]==k) cout<<l<<endl;else cout<<l-1<<endl; //已经确定数组中存在这个数,如果不是要找的值,说明我们找到是大于k的值,需要退一步return 0; }
4.A-B 数对
-
题目
链接: P1102 A-B 数对 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
给出一串正整数数列以及一个正整数 CCC,要求计算出所有满足 A−B=CA - B = CA−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个正整数 N,CN,CN,C。
第二行,NNN 个正整数,作为要求处理的那串数。
输出格式
一行,表示该串正整数中包含的满足 A−B=CA - B = CA−B=C 的数对的个数。
样例 1
样例输入 1
4 1 1 1 2 3
样例输出 1
3
提示
对于 75%75\\%75% 的数据,1≤N≤20001 \\leq N \\leq 20001≤N≤2000。
对于 100%100\\%100% 的数据,1≤N≤2×1051 \\leq N \\leq 2 \\times 10^51≤N≤2×105,0≤ai<2300 \\leq a_i <2^{30}0≤ai<230,1≤C<2301 \\leq C < 2^{30}1≤C<230。
-
第一次 AC 75%
#include<bits/stdc++.h> using namespace std;const int N=2010;int a[N];int main() {int n,k;cin>>n>>k;for(int i=0;i<n;i++)cin>>a[i];sort(a,a+n);int cnt=0;for(int i=0;i<n;i++){for(int j=i+1;j<n;j++){if(a[j]-a[i]==k)cnt++;}}cout<<cnt;return 0; }
暴力解题,好爽a
-
第二次 模拟的题解 AC100%
#include<bits/stdc++.h> using namespace std;typedef long long ll;const int N=2*1e5+10;map<ll,ll> m;ll a[N];int main() {ll n,k;cin>>n>>k;for(ll i=0;i<n;i++){cin>>a[i];m[a[i]]++; //记录每个数在数组中出现的次数}ll cnt=0;for(ll i=0;i<n;i++){ll t=a[i]-k; //t=A-Cif(t<=0) continue;cnt+=m[t]; //直接加上t出现的次数,map真不错}cout<<cnt;return 0;} //十年OI一场空,不开long long见祖宗
绷不住了,N范围开小了,找了半小时bug
-
反思
- 转换思路的重要性,题解中把 A-B=C 转换成 A-C=B,查找B的个数
- 利用 map 键值对来存 每一数在数组中出现的次数,然后就可以直接使用了
- 开 long long 不要犹豫