作者:指针不指南吗
专栏:蓝桥杯倒计时冲刺最后一周,复习学过的知识,刷题冲刺
题目
链接: 794. 高精度除法 - AcWing题库
给定两个非负整数(不含前导 0) A,B,请你计算 A/B 的商和余数。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共两行,第一行输出所求的商,第二行输出所求余数。
数据范围
1≤A的长度≤100000,
1≤B≤10000,
B 一定不为 0输入样例:
7 2
输出样例:
3 1
n次之后才 AC
#include
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
做的时候,不能只背模板,再想一下原因,为什么这么写,意义是什么!
题目
链接: 扫地机器人 - 蓝桥云课 (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≤ 1 0 5 10^5 105 ,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
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<
}
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
题目
链接: 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
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;
}
题目
链接: P1102 A-B 数对 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
给出一串正整数数列以及一个正整数 C C C,要求计算出所有满足 A − B = C A - B = C A−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。
输入格式
输入共两行。
第一行,两个正整数 N , C N,C N,C。
第二行, N N N 个正整数,作为要求处理的那串数。
输出格式
一行,表示该串正整数中包含的满足 A − B = C A - B = C A−B=C 的数对的个数。
样例 1
样例输入 1
4 1 1 1 2 3
样例输出 1
3
提示
对于 75 % 75\% 75% 的数据, 1 ≤ N ≤ 2000 1 \leq N \leq 2000 1≤N≤2000。
对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 2 × 1 0 5 1 \leq N \leq 2 \times 10^5 1≤N≤2×105, 0 ≤ a i < 2 30 0 \leq a_i <2^{30} 0≤ai<230, 1 ≤ C < 2 30 1 \leq C < 2^{30} 1≤C<230。
第一次 AC 75%
#include
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
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-C
if(t<=0) continue;
cnt+=m[t]; //直接加上t出现的次数,map真不错
}
cout<<cnt;
return 0;
}
//十年OI一场空,不开long long见祖宗
绷不住了,N范围开小了,找了半小时bug
反思