1083 借教室

题目1083中,暴力求解超时,需利用优化策略。通过前缀和与差分数组降低时间复杂度。二分查找结合前缀和能有效解决区间和问题,差分数组则是前缀和的逆运算,适用于订单修改查询。理解题意和数据结构是解题关键。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1083 借教室

这道题如果暴力的话肯定会超时,只能得45分
这道题的思路就是说每次这s-t天每一天都得减去借的桌子s,如果发现减去之后是一个负数说明这条订单不合理需要输出编号,那么我们暴力枚举的其实就是这个[s,t]区间,枚举的过程多大一千万,这个时间复杂度太高了,只能有45分
所以我们得进行一个优化,优化在哪里?肯定就是[s,t]区间得进行一个减少时间,用什么呢?
前缀和
前缀和其实是一个很简单的,其实表示方法就是s[i]=a[i]+a[i-1]+a[i-2]+a[i-3]+…+1,求出来前缀和数组就好了,那么我们的区间和然后区间和修改就好求了,O(1)复杂度,肯定就能通过了
但是…难就难在怎么求前缀和数组
我自己用函数来做了做,还是错了,所以,我得去看题解了
首先我们知道这道题是二分加上前缀和来做的
这道题其实用线段树很简单,直接干就行,但是我不想练线段树,直接用二分来练
所以我们这里使用差分数组,差分数组还得 配合着前缀和思想
我们有一组树,并且有一堆询问-----给定区间 l,r求l,r之间所有数的和
这样的话,暴力是肯定不行呢,那么前缀和怎么做?
用sum[i]存储前i个数的和,然后用sum[r]-sum[l-1]来表示l~r之间所有数的和,那么可以使用函数递归来实现


那么差分数组又是什么呢?只是前缀和的数组的逆运算
我们给定前i个数相邻两个数的差,求每一项a[i]
这就是用前一个值加上这个差就能求出来,比如diff[i]来记录a[i]-a[i-1]那么diff[i]+a[i-1]=a[i]了

---------------重新----------------
教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样
做题,一定要弄懂题意,算法,数据
数据非常重要
我们只需要每天提供 dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑,也就是说这个教室都是一样的,没有区别
至于这个订单的修改,也就是吧不满足,那么需要重新修改,如果有,需要通知哪一个申请人修改订单。这就是我们需要求的
题意我们都能理解
但是这个题的算法在哪里呢?
二分,前缀和,差分
首先:我们用暴力肯定是可以解决的,但不是正解
差分 差分是前缀和的逆运算,也就是一种dp思想

#include<iostream>
#include<cstring>
#include<cstdio> 
#include<cmath>
#include<string>
using namespace std;
int n,m;
int diff[1000011],need[1000011],rest[1000011],r[1000011],l[1000011],d[1000011];
bool isok(int x)//这里就是一个判断 
{
    memset(diff,0,sizeof(diff));
    for(int i=1;i<=x;i++)
    {
        diff[l[i]]+=d[i]; 
		/*
		diff[i]=diff[i]-diff[i-1]
		diff[l[i]]=diff[l[i]]-diff[l[i-1]]
		*/ 
        diff[r[i]+1]-=d[i]; //用差分数组来搞定这个差
		//接下来只需要判断差分数组就好了
		 
    }
    for(int i=1;i<=n;i++)
    {
        need[i]=need[i-1]+diff[i];//计算相邻的 
        if(need[i]>rest[i])return 0;//教室不够 
    }
    return 1;
} 
int main()
{
    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&rest[i]);//表示一个教室 
    for(int i=1;i<=m;i++)scanf("%d%d%d",&d[i],&l[i],&r[i]);//输入租借信息 
    int begin=1,end=m; 
    if(isok(m)){cout<<"0";return 0;}//全部满足租界 
    while(begin<end)
    {
        int mid=(begin+end)/2;
        if(isok(mid))begin=mid+1;//二分查找,查找的是什么 
        else end=mid;
    }
    cout<<"-1"<<endl<<begin;//寻找的是没有的个数 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值