ACWing蓝桥杯总结Day03

136 阅读2分钟

二分与前缀和

二分思想

整数二分

  1. 确定一个区间,使得目标值一定在区间中
  2. 找一个性质,满足两点
    • 性质具有二段性
    • 答案是二段性的分界点(95%)

两类模板:

  1. 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;

    }

  2. 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

}

例题

AcWing789.数的范围

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));
        }
    }
}

AcWing790. 数的三次方根

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()));
    }
}

习题

AcWing730.机器人跳跃问题

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);
    }
}

AcWing1221四平方和

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;
              }
          }

    }
}