二分和前缀和

二分的两种格式(边界不要不要搞混)

1)若数组中存在多个相同的元素,则该方法可求出最后一次出现的位置

while(L < R){
 	M = (L + R + 1) / 2;
    if(M <= ans){	//左半个区间包括了M
        L = M;
    }else{
        R = M - 1; 
    }
}

2)若数组中存在多个相同的元素,则该方法可求出首次出现的位置

while(L < R){
    M = (L + R) / 2;
    if(M < ans){	//左半个区间包括了M
        L = M + 1;
    }else{
        R = M;
    }
}

例:利用二分求三次方根

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int main(){
    double L = -10000, R = 10000;
    double n;
    scanf("%lf", &n);
    while(R - L > 1e-8){
        double M = (L + R) / 2;
        if(M * M * M >= n){
            R = M;
        }else{
            L = M;
        }
    }
    printf("%.6lf", L);
    return 0;
}

前缀和

1)一维前缀和

将求从第m~n个数的和从O(n)降到O(1)

S = Sn -Sm, 只需要开始时用一个数组存放所求的和

2)二维前缀和(容斥原理)

原矩阵:

*1 *7 *2 4
*3 *6 *2 8
2 1 2 3

S(x, y)表示点(x, y)及其左上方的所有数之和

求和公式(利用容斥原理):S(x, y) = S(x - 1, y) + S(x, y - 1) - S(x - 1, y - 1) + cur(x, y)

例如:如上*所标数字求S(2, 3), 2 * 3表格内的数字之和 = (2, 3)左边的 2 * 2表格 + (2, 3)上面的1 * 3表格 - 重叠部分的1 * 2表格 + 当前位置的数字

求和后矩阵:

1 8 10 14
4 17 21 33
6 20 26 41

进而利用容斥原理求二维的前缀和,即求从(x1, y1)到(x2, y2)的前缀和, 公式如下:

S = S(x2, y2) - S(x2, y1 - 1) - S(x1 - 1, y2) + S(x1 - 1, y1 - 1)

例:求子矩阵的和(知道矩阵的一个对角线上的两个端点即可确定子矩阵)
第一行包含三个整数 n,m,q。
接下来 n 行,每行包含 m 个整数,表示整数矩阵。
接下来 q 行,每行包含四个整数 x1,y1,x2,y2,表示一组询问。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int nums[1010][1010];
int main(){
    int m, n, q;
    scanf("%d%d%d", &m, &n, &q);
    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= n; j++){
            int cur;
            scanf("%d", &cur);
            //矩阵求和的公式:
            //S(x, y) = S(x - 1, y) + S(x, y - 1) - S(x - 1, y - 1) + cur(x, y)
            // printf("%d ", cur);
            nums[i][j] = nums[i - 1][j] + nums[i][j - 1] - nums[i - 1][j - 1] + cur;
            // printf("%d ", nums[i][j]);
        }
    while(q--){
        int x1, x2, y1, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        int ans = nums[x2][y2] - nums[x1 - 1][y2] - nums[x2][y1 - 1] + nums[x1 - 1][y1 - 1];
        printf("%d\n", ans);
    }
    return 0;
}
posted @ 2022-02-12 20:25  CDUT的一只小菜鸡  阅读(44)  评论(0编辑  收藏  举报