二分与前缀和

news2024/11/18 5:49:56

目录

🍈前言

❤二分

🌹二分

🌼数的范围

🌼数的三次方根

🌼特殊数字

🌼机器人跳跃问题

🌼四平方和

🌼分巧克力

🌹前缀和

🌼前缀和

🌼子矩阵的和

🌼激光炸弹

🌼K倍区间


🍈前言

❤二分

整数二分模板中,一个比较坑的点,就是C++整数向下取整的机制,考虑到这点,你才能写出AC 100%的代码

关键在于

1,对if ()后面条件的判断 

2,条件判断后,是先 l = mid,还是先 r = mid,如果是 l = mid,上面 mid = (l + r + 1) >> 1

3,纸上画图分析 目标值 和 区间的关系

4,避开下取整的坑,就能防止死循环 或 查找不到目标点

步骤

(1)区间

(2)二段性

(3)分界点 

(整数二分边界:区间只剩1个数)

(实数二分边界:区间长度足够小)

🌹二分

🌼数的范围

789. 数的范围 - AcWing题库

一道整数二分的题 

AC  代码

#include<iostream>
using namespace std;

int main()
{
    int n, q, k;
    cin>>n>>q;
    int a[n + 1];
    for (int i = 0; i < n; ++i)
        cin>>a[i];
    
    for (int i = 0; i < q; ++i) {
        cin>>k;
        // 二分左端点
        int l = 0, r = n - 1; // 区间范围
        while (l < r) {
            int mid = (l + r) >> 1;
            if (a[mid] >= k) 
                r = mid;
            else
                l = mid + 1;
        }
        if (a[r] == k) {
            cout<<r<<' '; // 退出循环时 l == r
            // 二分右端点
            l = r, r = n - 1;
            while (l < r) {
                int mid = (l + r + 1) >> 1; // l = mid,考虑到向下取整,mid要先+1
                if (a[mid] <= k)
                    l = mid;
                else
                    r = mid - 1; // 目标值必然在r左边, 不包括r
            }
            cout<<r<<endl; // 退出循环时 l == r
        }
        else
            cout<<"-1 -1"<<endl;
        
    }
    
    return 0;
}

🌼数的三次方根

一道实数二分的题

有单调性一定可以二分,没有单调性也可能可以二分。

(1)确定区间

(2)二段性

(3)边界
(4)注意double以及精度 <1e-8,以便保证6位小数的精度

AC   代码

#include<iostream>
#include<cstdio>
using namespace std;


int main()
{
    double n;
    cin>>n;
    double l = -50, r = 50; // 50的三次方已经超过10000了, 主要左端点是负数
    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;
}

🌼特殊数字

P1817 - [NewOJ Week 6] 特殊数字 - New Online Judge (ecustacm.cn)

1,两层for里最好遍历到  < 32,才能AC  100%,遍历到 < 31只能AC  67%

虽然2^30已经满足1e9了,不知道为什么不让过,总之范围大一点安全

2,先排序,再二分(因为二分需要二段性和边界)

3,用二分模板,最后需要分类讨论输入的 x 和数组中元素的大小对比

AC  代码

#include<iostream>
#include<algorithm>
using namespace std;

int a[1010], cnt; 

int main()
{
    // 预处理符合题目要求的二进制数字
    for (int i = 0; i < 32; ++i)
        for (int j = i + 1; j < 32; ++j) {
            a[cnt++] = (1 << i) + (1 << j);
        }
    // 先排序再二分
    sort(a, a + cnt);
    int t, x;
    cin>>t;
    while (t--) {
        cin>>x;
        // 二分
        int l = 0, r = cnt - 1; // 数组下标
        while (l < r) {
            int m = (l + r) >> 1;
            if (a[m] >= x)
                r = m;
            else
                l = m + 1;
        } // 退出循环后 l == r
        if (a[l] == x)
            cout<<0<<endl;
        else {
            int ans;
            if (a[l] > x)
                ans = (a[l] - x > x - a[l - 1]) ? x - a[l - 1] : a[l] - x;
            else
                ans = (x - a[l] > a[l + 1] - x) ? a[l + 1] - x : x - a[l];
            cout<<ans<<endl;
        }
    }

    return 0;
}

// 1 2 4 8 16 32
// 3 5 6 9 10 12 17 18 20 24 33 34 36 40 48

🌼机器人跳跃问题

730. 机器人跳跃问题 - AcWing题库

(1)

首先,为了确保二段性,我们用归纳法,可以得到,当初始能量 >= 某个值, 能量继续增大,还是满足条件

可以用二分

(2)

建议画图分析 while(l < r) 循环内部的操作

AC  代码

#include<iostream>
#include<cstdio>
using namespace std;

int n, h[100010];

bool check(int x)
{
    for (int i = 1; i <= n; ++i) {
        x = 2*x - h[i];
        if (x < 0) return false;
        if (x >= 1e5) return true; // 这里剪枝很重要,否则会爆long long
    }
    return true;
}

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        scanf("%d", &h[i]);
    int l = 0, r = 100000;
    while(l < r) {
        int m = (l + r) >> 1;
        if (check(m)) r = m;
        else l = m + 1;
    }
    printf("%d", l);
    return 0;
}

🌼四平方和

1221. 四平方和 - AcWing题库

(1)每次做题前,先分析时间复杂度,本题  N <= 5e6,因为是平方,每个数最大 2400 

(2)考虑到一般空间复杂度要求 1e9,时间复杂度要求1e8,此处只能枚举2个数

(3)N = a^2 + b^2 + c^2 + d^2,枚举a,b后,d = 根号(N - a^2 - b^2 - c^2),还有个c需要通过空间换时间得到

(4)具体就是

for       a.......
    for         b......... {
        t = N - a^2 - b^2;
        // 二分: 检查t是否在前面出现过O(logn)
    }

二分前,需要将所有数存在数组中,然后排序

(5)题目中联合主键顺序,即字典序最小

(6)代码中结构体Sum中定义了运算符重载👇

operator< 函数是一个比较运算符,它定义了Sum类型之间的小于关系。当我们使用sort等算法对Sum类型的数组进行排序时,实际上是按照<号运算符的比较结果来确定元素之间的相对位置

字典序最小的解释

(1)由于a从0开始遍历,每一种符合a = 0的可能都会遍历到,所以a是最小的

(2)同理,b从a开始,b一定是第二小的

(3)最后的c, d,定义一个结构体,按 s, c, d优先级的顺序小到大即可

AC  代码

#include<iostream>
#include<algorithm> //sort()
using namespace std;

const int N = 2500000;

struct Sum {
    int s, c, d; // 与预处理传入的一一对应
    bool operator <(const Sum &t)const // 结构体中重载 <
    {
        if (s != t.s) return s < t.s;
        if (c != t.c) return c < t.c;
        return d < t.d;
    }
}Sum[N];

int main()
{
    int n, m = 0;
    cin>>n;
    // 空间换时间,预处理两个数的平方和
    for (int c = 0; c*c <= n; ++c)
        for (int d = c; d*d + c*c <= n; ++d)
            Sum[m++] = {c*c + d*d, c, d}; // 与定义处一一对应
    
    sort(Sum, Sum + m);
    
    // 枚举a, b
    for (int a = 0; a*a <= n; ++a)
        for (int b = a; a*a + b*b <= n; ++b) {
            // 二分: Sum中找c*c + d*d
            int t = n - a*a - b*b;
            int l = 0, r = m - 1; // Sum[]的下标
            while (l < r) {
                int mid = (l + r) >> 1;
                if (Sum[mid].s >= t) r = mid;
                else l = mid + 1;
            } // 退出循环时, l == r
            if (Sum[l].s == t) {
                cout<<a<<" "<<b<<" "<<Sum[l].c<<" "<<Sum[l].d<<endl;
                return 0;
            }
        }
        return 0;
}

🌼分巧克力

1227. 分巧克力 - AcWing题库

AC  代码

#include<iostream>
#include<cstdio> // scanf(), printf()
using namespace std;

const int N = 100005;
int n, k, h[N], w[N];

bool check(int m)
{
    int res = 0;
    for (int i = 0; i < n; ++i) {
        res += (h[i] / m) * (w[i] / m);
        if (res >= k) return true; // 剪枝
    }
    return false;
}

int main()
{
    scanf("%d %d", &n, &k);
    for (int i = 0; i < n; ++i) scanf("%d %d", &h[i], &w[i]);
    int l = 0, r = 1e5;
    while (l < r) {
        int m = (l + r + 1) >> 1; // m表示边长
        if (check(m)) // check 表示个数
            l = m;
        else
            r = m - 1;
    }
    printf("%d", l);
    
    return 0;
}

🌹前缀和

🌼前缀和

795. 前缀和 - AcWing题库

AC  代码

#include<iostream>
#include<cstdio> 
using namespace std;

const int N = 100005;

int main()
{
    int n, m, a[N], s[N] = {0};
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        s[i] += s[i - 1] + a[i];   
    }
    int l, r;
    while (m--) {
        scanf("%d%d", &l, &r);
        printf("%d\n", s[r] - s[l - 1]);
    }
    return 0;
}

🌼子矩阵的和

796. 子矩阵的和 - AcWing题库

画图,容斥原理

(1)预处理前缀和数组👇

S(i, j) = S(i - 1, j) + S(i, j - 1) - S(i - 1, j - 1) + a(i, j)

(2)利用前缀和数组计算ans

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

(3)为防止越界,下标从 1~n

AC  代码

#include<iostream>
#include<cstdio>

const int N = 1005;

int main()
{
    int n, m, q, a[N][N], s[N][N];
    scanf("%d%d%d", &n, &m, &q);
    // 预处理前缀和数组
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= m; ++j) {
            scanf("%d", &a[i][j]);
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];
        }
    // 计算结果
    while (q--) {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        printf("%d\n", s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]);
    }
    return 0;
}

🌼激光炸弹

99. 激光炸弹 - AcWing题库

注意目标位置,可以理解为在点上。

在上题容斥原理的基础上,O( (n - R + 1) * (n - R + 1) ),枚举正方形右下角的点。

本题难点在于边界,而不是二维前缀和

再说说空间复杂度👇

5000 * 5000二维数组 int,= 2.5 * 10^7,两个二维数组a[][] 和 s[][] 就是 5 * 10^7

1 int = 4 byte

= 2 * 10^8 byte

1M = 1024 * 1024 byte

所以2个二维开到 2 * 10^8 / 10^6 = 200M > 168M

所以只能开1个 s[][]

tips: 为了防止初始越界,前缀和类型都从1开始

已经得到前缀和矩阵,如何计算ans,参考上题截图👇

AC  代码

有几个坑,详情看注释

#include<iostream>
#include<algorithm> //max()
using namespace std;

const int N = 5010;

int main()
{
    int cnt, R, s[N][N] = {0};
    cin>>cnt>>R;
    R = min(R, 5001); // 防止越界
    
    int x, y, w, n, m;
    
    n = m = R; // 防止 n, m 为0, 无法进入循环
    
    while (cnt--) {
        cin>>x>>y>>w;
        x++, y++; // 坐标1开始
        n = max(n, x), m = max(m, y); // 不越界
        s[x][y] += w;
    }
    // 预处理前缀和数组
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
            
    int ans = 0;
    // 枚举边长R正方形的右下角(i ,j)
    for (int i = R; i <= n; ++i)
        for (int j = R; j <= m; ++j)
            ans = max(ans, s[i][j] - s[i - R][j] - s[i][j - R] + s[i - R][j - R]);
    cout<<ans<<endl;
    
    return 0;
}

🌼K倍区间

1230. K倍区间 - AcWing题库

一维前缀和 + 同余

时间 O(n)

解释下同余👇

cnt[s[i] % k]++;     cnt[i] 统计余数为 i 的前缀和的个数

ans += cnt[i], 注意ans放前面,因为先出现余数相同的前缀和,才能 +=

同余意味着,( s[j] - s[i] ) % k == 0,满足题意

AC  代码

#include<iostream>
#include<cstdio>

const int N =  100005;
#define LL long long

int main()
{
    LL n, k, s[N] = {0}, cnt[N] = {0}, ans = 0; // LL防止爆int
    scanf("%lld%lld", &n, &k);
    
    // 读入 + 预处理前缀和
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &s[i]);
        s[i] += s[i - 1];
    }
    
    // 同余
    cnt[0] = 1; // 余数0直接加
    for (int i = 1; i <= n; ++i) {
        ans += cnt[s[i] % k]; // 先 ans+=
        cnt[s[i] % k]++; // 再cnt[]++
    }
    printf("%lld", ans);
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1025347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

html form表单高级用法

场景&#xff1a;想单纯使用表单内置的api完成提交&#xff0c;不使用js代码 代码如下&#xff1a; <form name"myForm" action"http://localhost:13734/form" method"post"><label>用户名<input type"text" name&qu…

SecureCRT SSH与FTP连接中文乱码

1、首先要保证服务端环境变量是UTF-8编码的 LANG”zh_CN.UTF-8″ 2、会话里面配置好字符编码&#xff1a;UTF-8 SSH会话的窗口就可以正常显示中文了&#xff0c;效果如下 3、打开FTP或者SFTP时进行文件传输时&#xff0c;列表窗口里面还是乱码&#xff0c;需要把SecureCRT安…

BENTLY 350015 127610-01数字量输入模块

数字输入功能&#xff1a; BENTLY 350015 127610-01模块通常用于监测和采集数字输入信号&#xff0c;例如开关状态、传感器状态等。 多通道&#xff1a; 这些模块通常具有多个输入通道&#xff0c;允许同时监测多个数字输入信号。 高精度&#xff1a; BENTLY 350015 127610-0…

四维轻云平台倾斜模型三种加载方式及单体化操作介绍

为了优化倾斜模型浏览效果&#xff0c;「四维轻云」v1.4.1针对倾斜模型新增了三种加载方式&#xff1b;此外&#xff0c;平台还增加了单体化等功能。但很多用户还不会使用这些功能&#xff0c;小编就来向大家介绍一些如何设置倾斜模型的三种加载方式和单体化操作。 一、倾斜模…

爬虫技术对携程网旅游景点和酒店信息的数据挖掘和分析应用

导语 爬虫技术是一种通过网络爬取目标网站的数据并进行分析的技术&#xff0c;它可以用于各种领域&#xff0c;如电子商务、社交媒体、新闻、教育等。本文将介绍如何使用爬虫技术对携程网旅游景点和酒店信息进行数据挖掘和分析&#xff0c;以及如何利用Selenium库和代理IP技术…

如何连接到远程桌面

远程桌面连接是一个非常有用的工具&#xff0c;尤其是当越来越多的人在家工作或使用自己的设备工作时。使用远程桌面连接软件&#xff0c;管理员即使不在您的设备附近&#xff0c;也可以解决问题&#xff0c;他们可以远程访问它并快速解决可能出现的任何问题。 什么是远程桌面…

初探微前端

微前端 一、微前端的背景和概述1.1 概念1.2 特点1.3 背景 二、微前端的实现方式2.1 服务端集成2.2 运行时集成 三、现有的解决方案3.1 single-spa3.2 qiankun3.3 micro-app 四、总结 &#x1f680;&#x1f680;&#x1f680;   随着互联网技术的不断发展&#xff0c;前端应用…

如何构建高效的接口自动化测试框架(文档+视频讲解)

在选择接口测试自动化框架时&#xff0c;需要根据团队的技术栈和项目需求来综合考虑。对于测试团队来说&#xff0c;使用Python相关的测试框架更为便捷。无论选择哪种框架&#xff0c;重要的是确保 框架功能完备&#xff0c;易于维护和扩展&#xff0c;提高测试效率和准确性。今…

最新版小说泛站群系统源码 小说泛目录站群源码系统程序/PHP语言(源码+教程)

源码简介&#xff1a; 新版小说泛目录站群系统网站源码&#xff08;小说站群源码&#xff09;&#xff0c;PHP小说泛站群系统程序&#xff0c;网站优化泛目录站群源码&#xff0c;新版小说泛站群系统源码&#xff0c;小说站群源码&#xff0c;小说泛目录站群源码PHP语言操作简…

《合成孔径雷达成像算法与实现》Figure5.4

clc clear close all%% 参数设置 Ta 128; % 脉冲持续时间 Ka -0.085; % 方位向调频率 alpha_OS [5,0.25]; …

《Python趣味工具》——自制emoji(4)计算机二级考试题

前面我们学习了如何制作emoji&#xff0c;相信你也是有很多想法了吧&#xff01;今天我们就来看看几道计算机二级考试真题。 1. 绘制套圈 使用turtle库的circle()函数和seth()函数绘制套圈。 最小的圆圈半径为10像素&#xff0c;不同圆圈之间的半径差是40像素。 ps:注意要和题…

【生物信息学】奇异值分解(SVD)

目录 一、奇异值分解&#xff08;SVD&#xff09; 二、Python实现 1. 调包np.linalg.svd() 2. 自定义 三、SVD实现链路预测 一、奇异值分解&#xff08;SVD&#xff09; SVD分解核心思想是通过降低矩阵的秩来提取出最重要的信息&#xff0c;实现数据的降维和去噪。 ChatG…

针对敏感数据的安全转录服务

即便在新冠肺炎疫情期间&#xff0c;继续保持了最高级别的机密性 新冠肺炎疫情带来的各种限制向所有服务提供商提出了挑战&#xff0c;促使提供商们想方设法采取更富想象力的新方法来满足客户的需求。澳鹏采用了一种由两种方案组成的工作机制&#xff0c;服务于客户机密材料的…

systrace使用注意事项

打开systrace文件报错&#xff1a;Unable to select a master clock domain because no path can be found from “SYSTRACE” to “LINUX_FTRACE_GLOBAL”. 使用systrace生成的trace.html文件无法打开&#xff0c;或者报上面的错误&#xff0c;可以选择下面这个方式&#xff1…

Springboot 实践(19)负载平衡配置与运用

前文Springboot 实践&#xff08;1&#xff09;至Springboot 实践&#xff08;18&#xff09;&#xff0c;我们分别讲解了springboot数据源配置、swagger-ui测试controller、整合security、整合Oauth2.0、服务注册、路由配置以及配置中心等单例功能开发&#xff0c;实现了各个系…

Avalonia开发(一)环境搭建

一、介绍 开源 GitHub&#xff1a;https://github.com/AvaloniaUI/Avalonia/多平台支持&#xff0c;包括Windows、mac OS、Linux、iOS、Android、Samsung Tizen&#xff08;很快支持&#xff09;、WebAssemblyIDE支持&#xff0c;Visual Studio扩展支持&#xff0c;JetBrains …

NLP技术如何为搜索引擎赋能

目录 1. NLP关键词提取与匹配在搜索引擎中的应用1. 关键词提取例子 2. 关键词匹配例子 Python实现 2. NLP语义搜索在搜索引擎中的应用1. 语义搜索的定义例子 2. 语义搜索的重要性例子 Python/PyTorch实现 3. NLP个性化搜索建议在搜索引擎中的应用1. 个性化搜索建议的定义例子 2…

学习笔记-接口测试(postman、jmeter)

目录 一、什么是接口测试 二、前端和后端 三、get请求和post请求的区别 四、cookie和session 五、接口测试的依据 六、HTTP状态码 七、通用接口用例 八、postman接口测试 九、Jmeter接口测试 一、什么是接口测试 通常做的接口测试指的是系统对外的接口&#xff0c;比…

【深度学习】 Python 和 NumPy 系列教程(九):NumPy详解:1、创建数组的n种方式

目录 一、前言 二、实验环境 三、NumPy 0. 多维数组对象&#xff08;ndarray&#xff09; a. 多维数组的属性 1. 创建数组 a. 使用numpy.array函数&#xff1a; b. 使用numpy.zeros函数 c. 使用numpy.ones函数 d. 使用numpy.arange函数 e. 使用numpy.linspace函数 …

旋转链表-双指针思想-LeetCode61

题目要求&#xff1a;给定链表的头结点&#xff0c;旋转链表&#xff0c;将链表每个节点向右移动K个位置。 示例&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k2 输出&#xff1a;[4,5,1,2,3] 双指针思想&#xff1a; 先用双指针策略找到倒数K的位置&#xff0c;也就是(…