P1083借教室

这篇博客介绍了如何解决洛谷P1083题目中的借教室问题。作者首先提到暴力求解方法,然后详细阐述了采用二分策略的优化思路,利用前缀和来判断订单是否满足条件。最后提供了AC代码实现。
摘要由CSDN通过智能技术生成

借教室

看看洛谷P1083的这道题。
这道题大概一看可能有些人就会想到用暴力的方法来做这道题。(反正本ruoji是这么做的)

先上一下四十五分的暴力代码(千万别抄,不是AC)

#include<bits/stdc++.h>
using namespace std;

int m,n;
int have[1000010];

bool run(int x,int y,int z){
   
	for(int i = y;i <= z;i++){
   
		if(have[i] < x){
   
			return true;
		}
		have[i]-=x;
	}
	return false;
}

int main()
{
   
	cin >> n >> m;
	for(int i = 1;i <= n;i++){
   
		cin >> have[i];
	}
	for(int i = 1;i <= m;i++){
   
		int borrow,start,end;
		cin >> borrow >> start >> end;
		if(run(borrow,start,end)){
   
			cout << -1 << endl << i;
			return 0;
		}
	}
	cout << 0;
	return 0;
} 

不过这不是正解,想要得到正解还得好好分析分析

本ruoju仔细想了想,想到了二分策略。(我为啥之前没想到呢?)
二分策略 很容易 想到,直接在订单编号中二分即可,

但是我们如何判断呢??

线段树是一种方法(但用了这个你也不需要二分了),我们运用于线段树功能相同的前缀和

设c[]数组为前缀和数组,则对于一个d[i],s[i],t[i],则将c[s[i]]+=d[i], c[t[i]+1]-=d[i]

证明:

在一个订单的起始天+要借的房间数量,在结束天的下一天减去要借的房间数量。设一个数组c[i],记录前缀和。读入的数据是d,s,t

c[s]:=c[s]+d;c[t+1]:=c[t+1]-d;

那么如果第i天在s和t之间,那么前i天的sum{c[i]}中有c[s],相当于已经记下第i天的订单数量了。如果第i天在t之后,前i天的sum{c[i]}中有c[s]和c[t],因为c[s]+d+c[t+1]-d=c[s]+c[t],所以这个订单只对s和t中间天数起作用。得证!
(具体操作详解代码中的check()函数)

好了,话不多说了,直接上AC代码咯

#include<bits/stdc++.h>
#define int long long   //习惯这样了 
using namespace std;

const int Max = 1000005;

struct node
{
   
	int d,s,t;
}a[Max];

int r[Max];
int c[Max];
int n,m;

bool check(int x){
   
	memset(c,0,sizeof(c));
	for(int i = 1;i <= x;i++){
   
		c[a[i].s]+=a[i].d;
		c[a[i].t+1]-=a[i].d;
	}
	int last = 0,now;
	for(int i = 1;i <= n;i++){
   
		now = last+c[i];
		if(now > r[i]){
   
			return false;
		}
		last = now;
	}
	return true;
}

signed main(){
   
	cin >> n >> m;
	for(int i = 1;i <= n;i++){
   
		cin >> r[i];
	}
	for(int i = 1;i <= m;i++){
   
		cin >> a[i].d >> a[i].s >> a[i].t;
	}
	int l = 0,r = m;
	if(check(m) == true){
   
		cout << 0 << endl;
		return 0;
	}
	while(l < r){
   
		int mid = (l + r)>>1;
		if(check(mid)){
   
			l = mid+1;
		}
		else{
   
			r = mid;
		}	
	}
	cout << -1 << endl;
	cout << l;
	return 0;
}

快走吧!
快走吧!
怎么还不走?
没有彩蛋的。
走吧!
走吧!

你这么倔强,那就给你一个飞机大战的c++小游戏吧!


#include<iostream>
#include<windows.h>
#include<conio.h>
#include<time.h>
#include<string>
using namespace std;
 
/*=============== all the structures ===============*/
 
typedef struct Frame
{
   
    COORD position[2];
    int flag;
}Frame;
 
 
/*=============== all the functions ===============*/
 
void SetPos(COORD a)// set cursor 
{
   
    HANDLE out=GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(out, a);
}
 
void SetPos(int i, int j)// set cursor
{
   
    COORD pos={
   i, j};
    SetPos(pos);
}
 
void HideCursor()
{
   
    CONSOLE_CURSOR_INFO cursor_info = {
   1, 0}; 
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
 
//把第y行,[x1, x2) 之间的坐标填充为 ch
void drawRow(int y, int x1, int x2, char ch)
{
   
    SetPos(x1,y);
    for(int i = 0; i <= (x2-x1); i++)
        cout<<ch;
}
 
//在a, b 纵坐标相同的前提下,把坐标 [a, b] 之间填充为 ch
void drawRow(COORD a, COORD b, char ch)
{
   
    if(a.Y == b.Y)
        drawRow(a.Y, a.X, b.X, ch);
    else
    {
   
        SetPos(0, 25);
        cout<<"error code 01:无法填充行,因为两个坐标的纵坐标(x)不相等";
        system("pause");
    }
}
 
//把第x列,[y1, y2] 之间的坐标填充为 ch
void drawCol(int x, int y1, int y2, char ch)
{
   
    int y=y1;
    while(y!=y2+1)
    {
   
        SetPos(x, y);
        cout<<ch;
        y++;
    }
}
 
//在a, b 横坐标相同的前提下,把坐标 [a, b] 之间填充为 ch
void drawCol(COORD a, COORD b, char ch)
{
   
    if(a.X == b.X)
        drawCol(a.X, a.Y, b.Y, ch);
    else
    {
   
        SetPos(0, 25);
        cout<<"error code 02:无法填充列,因为两个坐标的横坐标(y)不相等";
        system("pause");
    }
}
 
//左上角坐标、右下角坐标、用row填充行、用col填充列
void drawFrame(COORD a, COORD  b, char row, char col)
{
   
    drawRow(a.Y, a.X+1, b.X-1, row);
    drawRow(b.Y, a.X+1, b.X-1, row);
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值