图文详解!二分、前缀和、差分算法原理与实战应用全解析

二分,前缀和,差分算法

二分,前缀和,差分算法是解决大规模区间问题的关键优化方法,下面是笔者总结的知识点,仅供参考~

在这里插入图片描述

例题P1083借教室

在这里插入图片描述
输入样例

4 3 
2 5 4 3 
2 1 3 
3 2 4 
4 2 4

输出样例

-1 
2
算法思路

核心思想:二分查找 + 差分数组

  1. 二分查找
    • 确定第一个无法满足的订单编号。
    • 对订单进行二分,检查前 mid 份订单是否可行。
  2. 差分数组
    • 快速计算区间更新后的每天需求。
    • 差分数组 diff 记录区间变化,通过前缀和还原每天总需求。
  3. 可行性检查
    • 计算前 mid 份订单的总需求,若某天需求超过可用教室数,则返回 false
优化代码示例
#include<iostream>
#include<vector>
using namespace std;

int n,m;
vector<int> num(n);//存储每天租借的教室数量
struct Rent{
	int rentNum;
	int rentBegin;
	int rentEnd;
};
vector<Rent> rent(m);

//分配教室
int dealClass(const vector<int>& count,const vector<Rent>& arr){
	for(int i=1;i<=m;i++){//遍历处理每一份订单 
		for(int j=rent[i].rentBegin;j<=rent[i].rentEnd;j++){//遍历更新区间的每一个值 
			if(num[j] < rent[i].rentNum){//如果当前教室数量小于申请量 
				cout<<"-1"<<endl;
				cout<<i<<endl;
				return 0; 
			}
			num[j] -= rent[i].rentNum;
		}
		cout<<"0"<<endl;
		return 0;
	}
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>num[i];
	}
	for(int i=1;i<=m;i++){
		cin>>rent[i].rentNum>>rent[i].rentBegin>>rent[i].rentEnd;
	}

	dealClass(num,rent);
	return 0;
}
暴力双重循环
#include <iostream>
#include <vector>
using namespace std;

int n, m;
vector<int> r; // 存储每天可租借的教室数量
vector<int> diff; // 差分数组

// 分配教室并检查是否满足
bool allocate() {
    diff.assign(n + 2, 0); // 初始化差分数组
    
    for (int i = 0; i < m; ++i) {
        int d, s, t;
        cin >> d >> s >> t;
        
        // 更新差分数组
        diff[s] += d;
        if (t + 1 <= n) diff[t + 1] -= d;
    }

    // 计算前缀和并检查是否满足
    int current = 0;
    for (int i = 1; i <= n; ++i) {
        current += diff[i];
        if (current > r[i]) return false;
    }
    return true;
}

int main() {
    cin >> n >> m;
    r.resize(n + 1);
    
    for (int i = 1; i <= n; ++i) {
        cin >> r[i];
    }

    if (allocate()) {
        cout << 0 << endl;
    } else {
        cout << -1 << endl;
        // 这里需要重新找到第一个不满足的订单(暴力方法)
        // 由于原暴力方法无法高效找到,建议使用二分查找
        // 此处仅为示例,实际应使用二分查找
        cout << "1" << endl; // 示例输出,需修正
    }
    return 0;
}

暴力方法局限性:

  • 无法高效找到第一个不满足的订单
  • 时间复杂度高(O (nm))
  • 大数据量下会超时

建议优先使用二分查找 + 差分数组的优化方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值