一、代码AC截图
二、题目反思总结
Easy1
思路:二分查找套模板
#include<iostream>
using namespace std;
#include<cstring>
#include<vector>
int main()
{
int n, q;
int x;
cin >> n;//n是数组大小
vector<int>a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
cin >> q;
for (int i = 0; i < q; i++)
{
cin >> x;
int l = 0;
int r= n - 1;
while (l < r)
{
int mid =( r + l) / 2;
if (a[mid] >= x)r = mid;
else l = mid + 1;
}
if (a[l] != x) cout << "No" << endl;
else cout << "Yes" << endl;
}
return 0;
}
这里补充总结一下二分的模板
核心点在于:
1check(mid)的条件判断写法
2l还是r等于mid,如果是l=mid在mid的初始条件补上+1,r=mid不需要
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
作者:yxc
链接:https://www.acwing.com/blog/content/277/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
例题:
核心代码段
#include<iostream>
using namespace std;
#include<cstring>
#include<vector>
int main()
{
const int N= 100010;
int n, m;
int q[N];
for (int i = 0; i < n; i++)
scanf("%d", &q[i]);
while (m--)
{
int x;
scanf("%d", &x);
int l = 0, r = n - 1;
while (l < r)
{
int mid = (l + r) / 2;
if (q[mid] >= x) r = mid;//先找第一个大于等于x的数字的位置
else l = mid + 1;
}
if (q[l] != x) cout << "-1 -1" << endl;//如果二分出来的结果不等于x,也就是二分找到的最小的大于x的数不为x,那么x就不在该数组里面
else
{
cout << l << ' ';//把该数组中x的第一个位置输出
//接着找x的最大下角标
int l = 0, r = n - 1;
while (l < r)
{
int mid = (l + r + 1) / 2;
if (q[mid] <= x)l = mid;
else r = mid - 1;
}
cout << l << endl;
}
}
Easy2
思路:A-B=C,A,B都是最开始的数组a【】里面的,那么可以让C+B=A,把A值放在新数组b【】里面,然后在b【】数组里面查找a【】数组里面的值。用了两个函数,分别查找1第一个大于等于x的位置2最后一个大于等于x的位置,如果第一个都没有找到则说明没有x,那么可以跳过2的查找节省时间,如果第一个有找到,那么把两次下角标相减的差加1就可以得到b数组里面对应的a数组值的个数,用循环遍历a数组的值,并在b数组中一一查找求个数再把个数累加起来
#include<iostream>
using namespace std;
#include<cstring>
#include<vector>
#include <algorithm>
long long bsearch_1(long long l, long long r,const vector<long long>& b,long long target)
{
while (l < r)
{
int mid = (l + r)/2;
if (b[mid]>=target) r = mid;
else l = mid + 1;
}
if (b[l] !=target)
return -1;
return l;
}
long long bsearch_2(long long l, long long r,const vector<long long>& b,long long target)
{
while (l < r)
{
int mid =( l + r + 1)/2;
if (b[mid]<=target) l = mid;
else r = mid - 1;
}
return l;
}
int main()
{
long long flag1, flag2;
long long cnt = 0;
long long n, c;
cin >> n >> c;
vector<long long> a(n);
vector<long long> b(n);
for (long long i = 0; i < n; i++)
cin >> a[i];
for (long long i = 0; i < n; i++)
b[i] = a[i] + c;
sort(b.begin(), b.end());
for (long long k = 0; k < n; k++)
{
flag1 = bsearch_1(0, n - 1, b, a[k]);
if (flag1 < 0)
{
continue;
}
else
{
flag2 = bsearch_2(0, n - 1, b, a[k]);
}
cnt += flag2 - flag1 + 1;
}
cout << cnt;
}
特别注意的点
1数组b要记得排序一下才能二分查找
2结果开longlong才能过测试点,特别感谢
Medium1
思路:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool check(int mid, vector<vector<int>> &table,int n,int k)
{
int cnt = 0;
for (int i = 0; i < n; i++)
{
cnt += (table[i][0] / mid) * (table[i][1] / mid);
}
return cnt >= k;
}
int main()
{
int n, k;
cin >> n >> k;
vector<vector<int>> table(n, vector<int>(2));
for (int i = 0; i < n; i++)
{
for (int j = 0; j < 2; j++)
cin >> table[i][j];
}
int l = 1, r = 1e5;
while (l < r)
{
int mid = (l + r+1) / 2;
if (check(mid, table, n, k))l = mid;
else r = mid - 1;
}
cout << l << endl;
return 0;
}
Medium2
思路:答案序列具备单调性!!!
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool check(long long mid,vector<long long>&a,vector<long long>&b,long long n,long long m)
{
long long cnt = 0;
for (long long i = 0; i < n; i++)
{
if (a[i] < mid)
{
if (mid - a[i] <= b[i])
cnt += mid - a[i];
else
return false;
}
}
return cnt <= m;
}
int main()
{
long long n, m;
cin >> n >> m;
vector<long long>a(n);
vector<long long>b(n);
for (long long i = 0; i < n; i++)
cin >> a[i];
for (long long i = 0; i < n; i++)
cin >> b[i];
long long l = 0, r = 1e9;
while (l < r)
{
long long mid = (l + r+1) / 2;
if (check(mid, a, b, n, m)) l = mid;
else r = mid - 1;
}
cout << l<<endl;
return 0;
}
第一次写超时了,找了好久才发现是套的模板忘记+1然后死循环啦。。真是无语了。。被自己无语到。。也还是要多注意细节。
三、个人心得
二分答案真的好巧妙啊巧妙,只是有时候从具体问题中转化写check条件的时候还挺抽象的。模板一定要背对啊啊。。有公式就是快。。但如果背错了就悲哀了。。这几天再整理一下思路再找几个同类题多写写吧。第二次打卡get,坚持啊请坚持。