题解:P10051 [CCO2022] Rainy Markets
思维难度较大,感觉有个蓝题?
首先判断一个无解情况:
鉴于要输出方案,我们最好开数组来记录。
先设
大概就是要除去在第
设
我们可以从右向左贪心(具体待会简单解释以下)。
显然,向右侧多分配人是更优的(毕竟右边已经尽量优的处理过了)。
分配完之后,因为要使得买伞的人的数量少,就尽量多的原地不动,这样就用上了
实在不行的话,只能让剩余的人买伞了。
还是不行的话,就要让剩下的原地不动了(因为没法再分配了)。若剩下的人数大于了容量,便无解。
代码
#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]);
}
}