二分与前缀和
二分思想
整数二分
- 确定一个区间,使得目标值一定在区间中
- 找一个性质,满足两点
- 性质具有二段性
- 答案是二段性的分界点(95%)
两类模板:
-
ans是红区间的右端点
将[L,R]分成[L,M-1]和[M,R]
if M是红色的 说明ans仍然在[M,R]
else 说明 ans必然在[L,M-1]
while(L<R){
M = (L+R+1) / 2;
if M 红 L = M;
else R = M - 1;
}
-
ans是绿色区间的左端点
将[L,R]分成[L,M]和[M+1,R]
if M是绿色的 说明ans在[L,M]
else 说明ans在[M+1,R]
while(L<R){
M = (L+R) / 2;
if M 绿 R=M;
else L = M+1;
}
实数二分
将区间[L,R]划分为[L,M]和[M,R]
while(R - L > 1e^(-6)){
if ans在[M,R] L = M
else if ans在[L,M] R=M
}
例题
import java.util.Scanner;
public class AcWing789 {
static int[] arr;
/**
* 目标值在右区间的左端点, 二段性: arr[i] >= k
*/
static int findLeftBoundary(int k){
int l = 0;
int r = arr.length - 1;
while(l < r){
int mid = (l+r)/2;
if(arr[mid] >= k) r = mid;
else l = mid + 1;
}
return arr[l] == k ? l : -1;
}
/**
* 目标值在左区间的右端点, 二段性: arr[i] <= k
*/
static int findRightBoundary(int k){
int l = 0;
int r = arr.length - 1;
while(l < r){
int mid = (l+r+1)/2;
if(arr[mid] <= k) l = mid;
else r = mid - 1;
}
return arr[r] == k ? r : -1;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
arr = new int[n];
/*
* 查询次数
*/
int q = sc.nextInt();
for(int i = 0; i < n; ++i) arr[i] = sc.nextInt();
for(int i = 0; i < q; ++i){
int k = sc.nextInt();
System.out.println(findLeftBoundary(k) + " " + findRightBoundary(k));
}
}
}
public class AcWing790 {
static double l = -10000.0;
static double r = 10000.0;
static double sqrt3(double x) {
boolean isNegative = x < 0.0;
if(isNegative) x = -x;
while(r - l > 1e-8){
double mid = (l + r) / 2;
if(mid * mid * mid <= x) l = mid;
else r = mid;
}
return isNegative ? -l : l;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.printf("%.6f\n", sqrt3(sc.nextDouble()));
}
}
习题
import java.util.Scanner;
public class AcWing730 {
static int N;
static int[] H;
static long l = 1;
static long r = 100_000;
static boolean check(long e){
for(int i = 1; i <= N; ++i){
e += e - H[i];
if(e < 0) return false;
if (e >= 1e5) return true;
}
return true;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
H = new int[N + 1];
for(int i = 1; i <= N; i++) H[i] = sc.nextInt();
while(l < r){
long m = (l + r) >> 1;
if(check(m)) r = m;
else l = m + 1;
}
System.out.println(l);
}
}
import java.util.Scanner;
class Pair{
int c;
int d;
public Pair(int c, int d) {
this.c = c;
this.d = d;
}
}
public class Main {
static Pair[] arr;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
arr = new Pair[N + 1];
int threshold = (int) Math.sqrt(N);
for(int c = 0; c <= threshold; ++c) {
//保证 d >= c
for(int d = c; c*c + d*d <= N; ++d){
int index = c * c + d * d;
if(arr[index] != null) continue;
arr[index] = new Pair(c, d);
}
}
for(int a = 0; a <= threshold; ++a) {
//保证 b >= a
for(int b = a; b*b + a*a <= N; ++b) {
int index = N - a * a - b * b;
if(arr[index] == null) continue;
System.out.println(a + " " + b + " " + arr[index].c + " " + arr[index].d);
return;
}
}
}
}