二分:确定一个区间,使得答案一定在区间中
整数二分:
对mid的更新方式 , 当right = mid 时使用 left + ((right - left)>> 1)
left = mid 时 mid = left + (((right + 1) - left ) >> 1)
import java.util.*;
class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] arr = new int[n];
for (int j = 0; j < n; j++){
arr[j] = sc.nextInt();
}
for (int i = 0; i < m; i++){
int q = sc.nextInt();
int left = 0;
int right = n - 1;
while (left < right){
int mid = left + ((right - left)>>1);
if (arr[mid] >= q){
right = mid;
}else{
left = mid + 1;
}
}
if (arr[right] == q){
System.out.print(right+" ");
right = n - 1;
while(left < right){
int mid = left + (((right + 1) - left) >> 1);
if (arr[mid] <= q){
left = mid;
}else{
right = mid - 1;
}
}
System.out.println(left);
}else{
System.out.println("-1" + " " + "-1");
}
}
}
}
实数二分:
此题二分的关键在于找到一个最初始的可以满足条件的值,在以此值不断收缩边界即可算出答案
比如找到一个值E0,E0以后的所有值都满足不为负的条件,那么就可以收缩右边界,R = mid
import java.util.*;
class Main{
static int n = 0;
static int N = 100010;
static int[] h = new int[N];
public static boolean check(int mid){
int E = mid;
for (int i = 0; i < n; i++){
E = 2*E - h[i];
if (E >= 1e5) return true;
if (E < 0) return false;
}
return true;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
for (int i = 0; i < n; i++){
h[i] = sc.nextInt();
}
int left = 0;
int right = 100000;
while (left < right){
int mid = (left + right) / 2;
if (check(mid)) right = mid;
else left = mid + 1;
}
System.out.print(right);
}
}
import java.util.*;
import java.io.*;
class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int N = 225000;
int n = sc.nextInt();
List<int[]> list = new ArrayList<>();
for (int c = 0; c * c <= n; c++){
for (int d = c; c * c + d * d <= n; d++){
list.add(new int[]{c * c + d * d, c , d});
}
}
list.sort((o1, o2) -> {
if (o1[0] != o2[0]) return o1[0] - o2[0]; // 当前集合内不存在,相等的平方和就将较小的和排前面
return o1[1] - o2[1]; // 否则就将c较小的排前面
});
for (int a = 0; a * a <= n; a++){
for (int b = a; a * a + b * b <= n; b++){
int temp = n - a * a - b * b;
int left = 0;
int right = list.size() - 1; // 在集合中寻找
while (left < right){
int mid = left + right >> 1;
if (list.get(mid)[0] >= temp) right = mid; // 如果当前值大于等于期望值,将右边界收缩
else left = mid + 1;
}
if (list.get(left)[0] == temp) {
System.out.print(a + " " + b + " " + list.get(left)[1] + " " + list.get(left)[2]);
return;
}
}
}
}
}
此题二分的关键在于,当我们求出一个最小的满足条件的正方形的边长后,使左边界收缩去找最大值。
import java.util.*;
class Main{
static int N = 100010;
static int n = 0;
static int k = 0;
static int[] h = new int[N];
static int[] w = new int[N];
public static boolean check(int mid){
int res = 0;
for (int i = 0; i < n; i++){
res += (h[i] / mid) * (w[i] / mid);
if (res >= k) return true;
}
return false;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
for (int i = 0; i < n; i++){
h[i] = sc.nextInt();
w[i] = sc.nextInt();
}
int left = 1;
int right = 100000;
while (left < right){
int mid = left + (right + 1) >> 1; // mid 是 当前的边长
if (check(mid)) left = mid; // 当找到一个最小满足的值后开始收缩
else right = mid - 1; // 找到不满足的值,缩小当前值
}
System.out.print(right);
}
}
前缀和:求一个区间内 第 i 个数到 第 k 个数的和
定义 S0 = 0 , Si = a1 + a2 + ... + ai 可以推出 Si+1 = Si + ai+1 or Si = Si-1 + ai
即 算区间[L,R]的和可以表示为 : SR - SL-1 = aL + aL+1 + ...+ aR
模板如下:
import java.util.*;
class Main{
static int l = 0;
static int r = 0;
static int N = 100010;
static int n = 0;
static int m = 0;
static int[] a = new int[N]; // 表示原数组
static int[] s = new int[N]; // 表示前缀和数组
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for (int i = 1; i <= n; i++){
a[i] = sc.nextInt();
s[i] = s[i-1] + a[i]; // 前n个数的和
}
for (int i = 1; i <= m; i++){
l = sc.nextInt();
r = sc.nextInt();
System.out.println(s[r] - s[l-1]);
}
}
}
二维前缀和 : 求子矩阵的和
前缀和矩阵的i行j列表示原矩阵i行j列到左上角的所有值的和.
模板:
import java.util.*;
import java.io.*;
class Main{
static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));
static int n = 0;
static int m = 0;
static int q = 0;
static int N = 1010;
static int[][] a = new int[N][N];
static int[][] s = new int[N][N];
public static void main(String[] args) throws IOException {
String[] temp = bf.readLine().split(" ");
n = Integer.parseInt(temp[0]);
m = Integer.parseInt(temp[1]);
q = Integer.parseInt(temp[2]);
for (int i = 1; i <= n; i++){
String[] temp2 = bf.readLine().split(" ");
for (int j = 1; j <= m; j++) {
a[i][j] = Integer.parseInt(temp2[j-1]);
s[i][j] = s[i][j-1] + s[i-1][j] - s[i-1][j-1] + a[i][j];
}
}
for (int i = 1; i <= q; i++) {
String[] temp3 = bf.readLine().split(" ");
int x1 = Integer.parseInt(temp3[0]);
int y1 = Integer.parseInt(temp3[1]);
int x2 = Integer.parseInt(temp3[2]);
int y2 = Integer.parseInt(temp3[3]);
System.out.println(s[x2][y2] - s[x2][y1-1] - s[x1-1][y2] + s[x1 - 1][y1 - 1]);
}
}
}