[寒]C201-L6
650. 椅子危机
题目描述
你作为校长,正在筹办校园开放日,希望邀请学生和家长来参观,期间有n个公开课在不同教室开展。第i个公开课从时刻si分钟到时刻ti分钟,需要摆放xi把椅子。椅子从一个教室搬到另一个教室需要5分钟(假设人手足够多,不管搬几把椅子都是这个时间)。请问至少需要几把椅子?
输入输出格式
输入格式
输入文件为chair.in,输入第一行为正整数n,之后n行每行三个正整数si,ti,xi
输出格式
输出文件为chair.out,输出一个整数表示答案
输入输出样例
输入样例#1:
3
1 2 100
7 8 101
12 13 102
输出样例#1:
203
输入样例#2:
4
1 5 100
10 20 50
5 10 1
1 2 10
输出样例#2:
111
说明
样例说明: 样例1:课程1需要100把椅子,下课后都挪到课程2,课程2还需要额外1把。课程2来不及搬到课程3,所以课程3需要额外的102把椅子。共100+1+102=203把 样例2:课程1需要100把椅子,课程4需要10把椅子,课程1下课后搬到课程2,课程3必须自备1把椅子。共100+10+1=111把 数据规模: 对于50%的数据,1<=n<=500 对于75%的数据,1<=n<=2000 对于100%的数据,1<=n<=10000,si,ti,xi<=1000
模型元素:讲座(连续时间段)
输入样例
3
1 2 100
7 8 101
12 13 102
每个讲座的时间对应一个连续段,也就是区间
讲座开始时间是区间的左端点
讲座结束时间是区间的右端点
模型元素:椅子移动要5分钟
等等效于
算法1:模拟+计数器数组
输入第一行为正整数n,n<=10000,之后n行每行三个正整数si,ti,xi,保证都不超过1000。
时间范围很小
cnt[i]记录时刻i
需要多少把椅子
O(NR)
代码:100分
#include<bits/stdc++.h> using namespace std; const int N=10009; int n,cnt[N],s,t,x; int main(){ freopen("chair.in","r",stdin); freopen("chair.out","w",stdout); cin >> n; for(int i = 0;i < n;i++){ cin >> s >> t>> x; for(int j = s;j <= t+4;j++){ cnt[j] += x; } } cout << *max_element(cnt,cnt+N) << endl; return 0; }
算法2:差分 区间两端打标记
代码:100分
#include<bits/stdc++.h> using namespace std; const int N=10009; const int R=1009; int d[N],s[N],n; int main(){ freopen("chair.in","r",stdin); freopen("chair.out","w",stdout); cin>>n; int a,b,x; for(int i=1;i<=n;i++){ cin>>a>>b>>x; d[a]+=x; d[b+5]-=x; } for(int i=1;i<R;i++)//依次扫描 s[i]=s[i-1]+d[i]; cout<<*max_element(s+1,s+R)<<endl; return 0; }
736. 汪星人
题目描述
你是一只汪星人,地球毁灭后你回到了汪星,这里每天有n个小时,你需要为自己选择正好连续的m小时作为每天睡眠的时间。从凌晨开始,第i小时内的睡眠质量为xi,请问经过选择后,你的睡眠质量总和最大是多少?
输入输出格式
输入格式
输入文件dog.in输入第一行为正整数n,m,1<=m<=n<=100000. 第二行为n个整数依次代表每小时的睡眠质量,绝对值均不超过100
输出格式
输出文件dog.out输出一个整数
输入输出样例
输入样例#1:
5 2
1 -1 -1 -1 2
输出样例#1:
3
方法1:断环+拉直+克隆
断环+拉直+克隆
-1 | 2 | -3 | 1 | 7 | -2 | 4 | 5 | -1 | 2 | -3 | 1 | 7 | -2 | 4 | 5 |
断环+拉直+克隆
正整数n,m, 1<=m<=n<=100000
const int N=1000009;
int x[N],s[N],n,m;
高频易错点:环形问题克隆时,数组大小需要翻倍
代码:100分
#include<bits/stdc++.h> using namespace std; const int N=1000009; int x[N],s[N],n,m; int main(){ freopen("dog.in","r",stdin); freopen("dog.out","w",stdout); cin >> n >> m; for(int i = 1;i <= n;i++){ cin >> x[i]; } for(int i = n + 1;i <= n*2;i++){ x[i] = x[i-n]; } s[0] = 0; for(int i = 1;i <= n*2;i++){ s[i] = s[i - 1] + x[i]; } int ans = s[m]; for(int i = m + 1;i <= n*2;i++){ ans = max(ans,s[i]-s[i-m]); } cout << ans << endl; return 0; }
方法2:首尾情况分类
首尾情况分类
首尾不相连
首尾相连
首尾不相连:
-1 | 2 | -3 | 1 | 7 | -2 | 4 | 5 |
环形问题简化为直线型
首尾相连:
-1 | 2 | -3 | 1 | 7 | -2 | 4 | 5 |
左侧共i个 右侧共m-i个
|| || || ||
1 i n-m+i n
2种解释
加法:s[i] + (s[n]-s[n-m+i])
减法:s[n] – (s[n-m+i]-s[i])
补集转换
代码:100分
#include<bits/stdc++.h> using namespace std; const int N=1000009; int x[N],s[N],n,m;//定义两个数组x和s+int类型的n和m int main(){ freopen("dog.in","r",stdin); freopen("dog.out","w",stdout); cin>>n>>m; for(int i = 1;i <= n;i++){ cin >> x[i];//输入 } for(int i = n + 1;i <= n*2;i++){ x[i] = x[i-n];//克隆数组 } s[0]=0; for(int i = 1;i <= n*2;i++){ s[i] = s[i - 1] + x[i];//计算s[i]数组的前缀和 } int ans = s[m];//ans初始化 for(int i = m + 1;i <= n*2;i++){ ans = max(ans,s[i]-s[i-m]);//打擂台找出最大值 } cout<<ans<<endl;//输出答案 return 0; }
2667. 高手集训
题目描述
太戈编程团队聚集了本市众多的编程高手。你作为总教练,要为高手们安排集训计划。课程表里有连续的n天可以供你选择,每天都有专题课程。其中第i天的专题趣味程度为h[i]。假设你选择了其中连续的若干天,从第l天到第r天。那么,
训练效果 = h[l]*1 + h[l+1]*2 + ... + h[r]*(r-l+1)
随着训练的深入进行,每天的趣味程度会得到更多倍数的效果。
目前有m种训练方案,每种方案由起始时间和结束时间来描述。请对每种方案输出训练效果。
输入输出格式
输入格式
输入文件training.in,输入第一行为正整数n和m, 均不超过100000。第二行为n个正整数代表每天专题的趣味程度,均不超过100000。随后共m行,每行为两个正整数l,r, 保证1<=l<=r<=n。
输出格式
输出文件training.out,输出一行共m个整数,由空格隔开。
输入输出样例
输入样例#1:
3 2
5 6 7
1 3
2 3
输出样例#1:
38 20
【说明】5*1+6*2+7*3=38;6*1+7*2=20。
代码:100分
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 100009; ll n, m, h[N], s[N], g[N]; int main(){ freopen("training.in", "r", stdin); freopen("training.out", "w", stdout); cin >> n >> m; for (ll i=1; i<=n; i++) cin >> h[i]; for (ll i=1; i<=n; i++){ s[i] = s[i-1] + h[i]; g[i] = g[i-1] + h[i] * i; } for (ll i=1; i<=m; i++){ ll l, r; cin >> l >> r; ll ans = g[r] - g[l-1] - (s[r] - s[l-1]) * (l-1); cout << ans << " "; } return 0; }