二分答案
二分一般直接二分答案mid,然后利用题目中的某个限制来检验这个mid是否是正确。
不正确就接着分。
一般框架:
int l, r;
while (l <= r) {
int mid = (l + r) / 2;
if (check(mid)) 答案就是mid;
else 根据题意,l = mid + 1 或者 r = mid - 1;
}
代码:
#include <cstdio>
const int MAXN = 5e4 + 7;
int s, n, m, a[MAXN];
int check(int x) {
int last = 0, re = 0;
for (int i = 1; i <= n + 1; i++)
if (a[i] - last < x) re++;
else last = a[i];
return re;
}
int main() {
scanf("%d%d%d", &s, &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
a[n + 1] = s;
int l = 1, r = s, ans = 0;
while (l <= r) {
int mid = (l + r) >> 1;
int f = check(mid);
// printf("when mid = %d, f = %d
", mid, f);
if (f <= m) l = mid + 1, ans = mid;
else r = mid - 1;
}
printf("%d
", ans);
return 0;
}
对于10% 的数据,有 1 ≤n ,m≤10;
对于30% 的数据,有 1 ≤n ,m≤500 ;
对于50% 的数据,有 1 ≤n ,m≤5,000;
对于70% 的数据,有 1 ≤n ,m≤10,000 ;
对于100%的数据,有 1 ≤n ,m≤200,000,0 < wi, vi≤10^6,0 < S≤10^12,1 ≤Li ≤Ri ≤n 。
首先,单纯的二分。
#include <cstdio>
#include <cstring>
#include <cmath>
#define ll long long
const int MAXN = 200007;
ll n, m, s, v[MAXN], w[MAXN], q[MAXN][2], rez = 1e13, retn;
ll check(ll x) {
ll ans = 0, f = 0, retn = 0;
for (ll i = 1; i <= m; i++) {
f = 0, ans = 0;
for (ll j = q[i][0]; j <= q[i][1]; j++)
if (w[j] >= x) ans += v[j], f++;
retn += ans * f;
}
retn = s - retn;
return retn;
}
int main() {
scanf("%lld%lld%lld", &n, &m, &s);
for (int i = 1; i <= n; i++) scanf("%lld%lld", &w[i], &v[i]);
for (int i = 1; i <= m; i++) scanf("%lld%lld", &q[i][0], &q[i][1]);
int l = 0, r = 1e6 + 1;
while (l <= r) {
ll mid = (l + r) / 2;
ll p = check(mid);
if (p > 0) {
if (p < rez) rez = p;
r = mid - 1;
} else if (!p) {
printf("0
");
return 0;
} else {
p = -p;
if (p < rez) rez = p;
l = mid + 1;
}
// printf("%lld
", p);
}
printf("%lld
", rez);
return 0;
}
check() 里是 n^2 的,肯定是A不了的,只过了50%的数据。
于是我们来想一想优化。
前缀和优化!