简单的二分查找——二分(3)
题目来源:洛谷 P1873 砍树
[原题](P1873 砍树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn))
共十个测试点
题解
WA代码1:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int a[maxn];
int n, m;
int ans;
int sum(int x, int pos)
{
int sum = 0;
for (int i = pos; i <= n; ++i)
sum += (a[i] - x);
return sum;
}
int solve()
{
int l = 1, r = n, mid;
while (l < r)
{
mid = (l + r) / 2;
if (sum(a[mid], mid) == m)
return a[mid];
else if (sum(a[mid], mid) > m)
{
l = mid + 1;
}
else
{
r = mid;
}
}
int anx = a[l - 1];
r = a[l];
while (anx < r)
{
mid = (anx + r) / 2;
if (sum(mid, l) == m)
return mid;
else if (sum(mid, l) > m)
{
anx = mid + 1;
}
else
{
r = mid;
}
}
return anx;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
ans = solve();
printf("%d", ans);
return 0;
}
错误分析:
判断条件错误。
测试点通过情况:
#2,#3,#4,#5,#6,#7,#8,#9,#10 WA
WA代码2:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int a[maxn];
int n, m;
int ans;
int sum(int x, int pos)
{
int sum = 0;
for (int i = pos; i <= n; ++i)
{
if (a[i] >= x)
sum += (a[i] - x);
else
sum += 0;
}
return sum;
}
int solve()
{
int f;
int l = 1, r = n, mid;
while (l < r && f != (r - l))
{
f = r - l;
mid = (l + r) / 2;
if (sum(a[mid], mid) == m)
return a[mid];
else if (sum(a[mid], mid) > m)
{
l = mid;
}
else
{
r = mid;
}
}
int anx = a[l];
r = a[l + 1];
while (anx < r && f != (r - anx))
{
mid = (anx + r) / 2;
if (sum(mid, l + 1) == m)
return mid;
else if (sum(mid, l + 1) > m)
{
anx = mid;
}
else
{
r = mid;
}
}
return anx;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
ans = solve();
printf("%d", ans);
return 0;
}
错误分析:
数据范围错误。
测试点通过情况:
#3,#9,#10 WA
AC代码1:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
long long int a[maxn];
long long int n, m;
long long int ans;
long long int sum(long long int x, long long int pos)
{
long long int sum = 0;
for (long long int i = pos; i <= n; ++i)
{
if (a[i] >= x)
sum += (a[i] - x);
else
sum += 0;
}
return sum;
}
long long int solve()
{
long long int f;
long long int l = 1, r = n, mid;
while (l < r && f != (r - l))
{
f = r - l;
mid = (l + r) / 2;
if (sum(a[mid], mid) == m)
return a[mid];
else if (sum(a[mid], mid) > m)
{
l = mid;
}
else
{
r = mid;
}
}
long long int anx = a[l];
r = a[l + 1];
while (anx < r && f != (r - anx))
{
mid = (anx + r) / 2;
if (sum(mid, l + 1) == m)
return mid;
else if (sum(mid, l + 1) > m)
{
anx = mid;
}
else
{
r = mid;
}
}
return anx;
}
int main()
{
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; ++i)
scanf("%lld", &a[i]);
sort(a + 1, a + n + 1);
ans = solve();
printf("%lld", ans);
return 0;
}
AC代码2:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
long long int n, m;
long long int l, r = -1, mid;
long long int a[maxn];
// 二分法求出答案
// 对结果进行二分,而非对数据二分
long long int solve(long long int x)
{
long long int sum = 0;
for (int i = 1; i <= n; ++i)
{
if (a[i] > x)
sum += (a[i] - x);
}
return sum;
}
int main()
{
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; ++i)
{
scanf("%lld", &a[i]);
r = max(r, a[i]);
}
long long int ans = 0;
while (l <= r)
{
mid = (l + r) / 2;
ans = solve(mid);
if (ans >= m)
l = mid + 1;
else
r = mid - 1;
}
printf("%lld", l - 1);
return 0;
}