洛谷P1083借教室

原题跳转链接点击此处跳转洛谷
下面是我写的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//前缀和数组
#include <iostream>
using namespace std;
int n,m;
int r[1000005];
int d[1000005],s[1000005],t[1000005];
long long sum[1000005]={0};//前缀和数组
//4 3
//2 5 4 3
//2 1 3
//3 2 4
//4 2 4
//前缀和数组的维护过程:
//sum[1]=2
//sum[2]=3
//sum[2]=7
//sum[3]=sum[2]+sum[3]=7+0=7
//sum4=sum3+sum4-d1=0+7-2=5
//本题前缀和数组记录某天一共需要教室的数量 但是常规构建该数组的时间复杂度为n^2 利用前缀和思想 时间复杂度为n
int main()
{
cin>>n>>m;
//第i天可供租借教室的数量
for(int i=1;i<=n;i++)
{
cin>>r[i];
}
for(int i=1;i<=m;i++)
{
cin>>d[i]>>s[i]>>t[i];
sum[s[i]]+=d[i];
sum[t[i]+1]-=d[i];
}
//时间复杂度 n*m<=n^2
int rejectNum=1e9;//存放需要重新申请的订单号在1到m之间不超过10的6次方
for(int i=1;i<=n;i++)
{
sum[i]+=sum[i-1];
if(sum[i]>r[i])
{
long long ans=sum[i];
int j;
for(j=m;j>=1;j--)
{
ans-=d[j];
if(ans<=r[i]) break;
}
//则需要停止教室的分配 这是题干要求 所以要输出第一个导致不能满足要求的申请人
rejectNum=min(rejectNum,j);
if(rejectNum==1) break;//不需要再遍历了 第一份订单就发通知单了 相当于剪枝
}
}
if(rejectNum==1e9)
{
cout<<0<<endl;
}
else{
cout<<-1<<endl;
cout<<rejectNum<<endl;
}
return 0;
}

本题的考察点是前缀和数组
我们要做的就是维护前缀和数组+二分查找优化查找时间复杂度
因为本题用for循环时间复杂度会比较高

[视频内嵌代码]