借教室
看看洛谷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);