P10051 [CCO 2022] Rainy Markets
题目背景
由于数据包过大,本题无法上传全部数据。
题目描述
有 NNN 个公交车站,标号为 1,…,N1, \ldots, N1,…,N。第 iii 个公交车站可以容纳 BiB_{i}Bi 个人。
对于每个 i∈{1,…,N−1}i \in\{1, \ldots, N-1\}i∈{1,…,N−1},有一条人行道连接公交车站 iii 和公交车站 i+1i+1i+1,中间有一个露天市场。第 iii 个市场有 UiU_{i}Ui 把雨伞出售,每把雨伞的价格为 111。
现在,有 PiP_{i}Pi 个人在第 iii 个市场里面,所有的公交车站都是空的。
突然,天开始下雨,市场 iii 的每个人都必须在三种方案中选择一种:
- 去公交车站 iii;
- 去公交车站 i+1i+1i+1;
- 留下来买一把雨伞。
如果一个人无法在某个公交车站下或者买一把雨伞,他们就会淋湿。
你需要回答如果在最优的安排方案下,能否确保每个人都能不被雨淋湿。如果是的话,你需要给出他们需要花费的最少的钱,以及每个人应该移动到哪个公交车站。
输入格式
第一行包含一个整数 NNN。
第二行包含 NNN 个用空格分隔的整数 Bi (1≤i≤N)B_{i}\ (1 \leq i \leq N)Bi (1≤i≤N),表示公交车站 iii 的容量。
第三行包含 N−1N-1N−1 个用空格分隔的整数 Pi (1≤i≤N−1)P_{i}\ (1 \leq i \leq N-1)Pi (1≤i≤N−1),表示市场 iii 的人数。
第四行包含 N−1N-1N−1 个用空格分隔的整数 Ui (1≤i≤N−1)U_{i}\ (1 \leq i \leq N-1)Ui (1≤i≤N−1),表示市场 iii 出售的雨伞的数量。
输出格式
如果每个人都能在雨伞或公交车站下,输出 N+1N+1N+1 行:
- 第一行输出一行
YES。 - 第二行输出一个整数,表示包含在雨伞上花费的最少的钱。
- 接下来的 N−1N-1N−1 行,每行输出三个用空格分隔的整数分别表示市场 i (1≤i≤N−1)i\ (1\leq i \leq N-1)i (1≤i≤N−1) 移动到公交车站 iii 的人数,市场 iii 买雨伞的人数,市场 iii 移动到公交车站 i+1i+1i+1 的人数。
如果有多种合法方案,你可以输出任意一种。
否则,输出一行 NO。
输入输出样例 #1
输入 #1
3
10 15 10
20 20
0 0
输出 #1
NO
输入输出样例 #2
输入 #2
3
10 15 10
20 20
0 11
输出 #2
YES
5
10 0 10
5 5 10
说明/提示
样例 1 解释
公交车站有 353535 个空位,没有雨伞出售,但市场有 404040 个人,所以答案是 NO。
样例 2 解释
市场 111 中的 101010 个人会去公交车站 111,没有人会买雨伞,101010 个人会去公交车站 222。
市场 222 中的 555 个人会去公交车站 222,555 个人会留下来买雨伞,101010 个人会移动到公交车站 333。
总共购买了 555 把雨伞,花费了 555。
数据范围
对于所有的数据,有 2≤N≤1062 \leq N \leq 10^{6}2≤N≤106,0≤Bi≤2⋅1090 \leq B_{i} \leq 2 \cdot 10^{9}0≤Bi≤2⋅109,0≤Pi,Ui≤1090 \leq P_{i},U_{i} \leq 10^{9}0≤Pi,Ui≤109。
| 子任务编号 | 分值 | NNN | BBB | PPP | UUU |
|---|---|---|---|---|---|
| 111 | 202020 | 2≤N≤1062 \leq N \leq 10^{6}2≤N≤106 | $0 \leq B_{i} \leq 2 \cdot 10^{9} $ | 0≤Pi≤1090 \leq P_{i} \leq 10^{9}0≤Pi≤109 | Ui=0U_{i}=0Ui=0 |
| 222 | 202020 | 2≤N≤20002 \leq N \leq 20002≤N≤2000 | 0≤Bi≤4000 \leq B_{i} \leq 4000≤Bi≤400 | $ 0 \leq P_{i} \leq 200$ | 0≤Ui≤2000 \leq U_{i} \leq 2000≤Ui≤200 |
| 333 | 242424 | 2≤N≤40002 \leq N \leq 40002≤N≤4000 | 0≤Bi≤40000 \leq B_{i} \leq 40000≤Bi≤4000 | 0≤Pi≤20000 \leq P_{i} \leq 20000≤Pi≤2000 | 0≤Ui≤20000 \leq U_{i} \leq 20000≤Ui≤2000 |
| 444 | 363636 | 2≤N≤1062 \leq N \leq 10^{6}2≤N≤106 | 0≤Bi≤2⋅1090 \leq B_{i} \leq 2 \cdot 10^{9}0≤Bi≤2⋅109 | 0≤Pi≤1090 \leq P_{i} \leq 10^{9}0≤Pi≤109 | 0≤Ui≤1090 \leq U_{i} \leq 10^{9}0≤Ui≤109 |
C++实现
#include<iostream>
using namespace std;
#define int long long
const int N=1e6+10;
int n;
int b[N],p[N],u[N];
int f[N];
int l[N],r[N],buy[N];
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lld",&b[i]);
}
for(int i=1;i<n;i++){
scanf("%lld",&p[i]);
}
for(int i=1;i<n;i++){
scanf("%lld",&u[i]);
if(u[i]+b[i]+b[i+1]<p[i]){
cout<<"NO";
return 0;
}
}
for(int i=1;i<=n;i++){
f[i]=max(0ll,b[i]-max(p[i-1]-f[i-1],0ll));
}
long long res=0;
for(int i=n-1;i;i--){
r[i]=min(p[i],b[i+1]-l[i+1]);
p[i]-=r[i];
l[i]=min(p[i],f[i]);
p[i]-=l[i];
buy[i]=min(p[i],u[i]);
p[i]-=buy[i];
l[i]+=p[i];
res+=buy[i];
if(l[i]>b[i]){
cout<<"NO";
return 0;
}
}
printf("YES\n%lld\n",res);
for(int i=1;i<n;i++){
printf("%lld %lld %lld\n",l[i],buy[i],r[i]);
}
}

后续
接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容
1587

被折叠的 条评论
为什么被折叠?



