> 文章列表 > 蓝桥杯刷题冲刺 | 倒计时7天

蓝桥杯刷题冲刺 | 倒计时7天

蓝桥杯刷题冲刺 | 倒计时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 个方格区域组成,如下图所示。

    蓝桥杯刷题冲刺 | 倒计时7天

    走廊内部署了 K 台扫地机器人,其中第 i 台在第 A i 个方格区域中。已知扫地机器人每分钟可以移动到左右相邻的方格中,并将该区域清扫干净。

    请你编写一个程序,计算每台机器人的清扫路线,使得

    1. 它们最终都返回出发方格,
    2. 每个方格区域都至少被清扫一遍,
    3. 从机器人开始行动到最后一台机器人归位花费的时间最少。

    注意多台机器人可以同时清扫同一方块区域,它们不会互相影响。

    输出最少花费的时间。 在上图所示的例子中,最少花费时间是 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<N10510^5105 ,1≤A iN

    输出描述

    输出一个整数表示答案。

    输入输出样例

    示例

    输入

    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;
    }
    
  • 二分模板 复习一下

    1. 找某个值在区间里面是否存在
    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 }}
    
    1. 返回左边 起始值
      int l=0,r=n;while(l<r){int mid=l+r>>1;if(check(mid)>=k) r=mid;   //起始节点else l=mid+1;}
    
    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;}
    
  • 反思

    什么问题可以运用二分搜索算法技巧?

    1. 首先,你要从题目中抽象出一个自变量 x,一个关于 x 的函数 f(x),以及一个目标值 target

    2. 同时,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 = CAB=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

    输入格式

    输入共两行。

    第一行,两个正整数 N,CN,CN,C

    第二行,NNN 个正整数,作为要求处理的那串数。

    输出格式

    一行,表示该串正整数中包含的满足 A−B=CA - B = CAB=C 的数对的个数。

    样例 1

    样例输入 1

    4 1
    1 1 2 3
    

    样例输出 1

    3
    

    提示

    对于 75%75\\%75% 的数据,1≤N≤20001 \\leq N \\leq 20001N2000

    对于 100%100\\%100% 的数据,1≤N≤2×1051 \\leq N \\leq 2 \\times 10^51N2×1050≤ai<2300 \\leq a_i <2^{30}0ai<230,1≤C<2301 \\leq C < 2^{30}1C<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

  • 反思

    1. 转换思路的重要性,题解中把 A-B=C 转换成 A-C=B,查找B的个数
    2. 利用 map 键值对来存 每一数在数组中出现的次数,然后就可以直接使用了
    3. 开 long long 不要犹豫

Alt