二分问题边界一直很头疼,可能死循环或者答案老是差一点点。每次到二分可能还要花一段时间确定边界。让人套模板还要改,是非常不能接受的事情。
不过
既然二分问题难办
我们直接掀掉桌子 不能解决问题,就把问题源头解决掉(掀桌子(╯‵□′)╯︵┻━┻)
二分复杂度logn级别,1e9也才一点点。几乎微乎其微,那么我再增加一点点就加个常数不过分吧
while (L + 1 < R) {
int mid = (L +R) / 2 ;
if (check (mid)) L = mid ;
else R = mid ;
}
其实我们不难发现,有时候,答案错误就是+1-1的问题,在acm中你可能多提交几次,就过了
所以我们索性二分到差不多就行了,while (L + 1 < R)变成while (L + 10 < R)
剩下的直接交给暴力遍历
卡常分析 :
没有哪个官方会卡个位数的,所以放心用
下面是个简单又经典的二分答案例子:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int, int> PII;
#define pb(s) push_back(s)
#define sz(s) ((int)s.size())
#define x first
#define y second
#define ms(s, x) memset(s, x, sizeof(s))
#define all(s) s.begin(), s.end()
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int N = 100010;
LL n, k;
int solve()
{
cin >> n >> k;
std::vector<LL> a(n);
LL l = 0, r = 2e14;
LL tmpl = 0;
LL tmpr = 0;
LL ans = 0;
for (int i = 0; i < n; ++i)
cin >> a[i];
LL op;
for (int i = 0; i < n; ++i)
op += a[i];
if (op < k)
{
cout << -1;
return 0;
}
auto check = [&](LL x)
{
LL res = 0;
for (int i = 0; i < n; ++i)
{
res += a[i] / x;
}
return res >= k;
};//可以用普通函数
while (l + 10 < r)
{
LL mid = l + r >> 1;
if (check(mid))
{
l = mid;
tmpl = l;
}
else
{
r = mid;
tmpr = r;
}
}//增加模糊区间,方便遍历
for (LL i = tmpl; i < tmpr; i++)
{
if (check(i))
{
ans = i;
}
else
break;
}
cout << ans << '\n';
return 0;
}
int main()
{
ios_base ::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cout << setiosflags(ios::fixed) << setprecision(2);
int t = 1;
while (t--)
{
solve();
}
return 0;
}
轻轻松松拿下,二分边界还需要动脑?