题解:P10001 [集训队互测 2023] 优惠购物
Smart_Jason · · 题解
[集训队互测 2023] 优惠购物
题目大意是给定
考虑直接啥也不用,大手一挥,全款拿下所有商品,然后此时再考虑在哪里使用优惠卷是最优的,我们记一个位置使用了
首先第一部分肯定是使用
那这个策略可以直接从前往后扫,记录当前还剩多少个优惠卷,尽可能的使用就好了。
然后再考虑第二阶段,这个时候你的选择应该是花
于是这一段你考虑怎么怎么贪心的取,因为获得的优惠卷会减少,所以你尽可能地在后面去选,也就是从后往前枚举,记一个
然后在考虑如果还有剩的第三部分,这时候我们要花一个物体上
那么一个位置能花的优惠卷就是
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
#define ll long long
int n,m,c,a[N],b[N],us[N],id[N];
ll s[N];
struct tree{
int lz;
ll minn;
}tr[N<<2];
inline void pushup(int x){ tr[x].minn=min(tr[x<<1].minn,tr[x<<1|1].minn); }
inline void pushtag(int x,int val){ tr[x].minn+=val,tr[x].lz+=val; }
inline void pushdown(int x){ pushtag(x<<1,tr[x].lz),pushtag(x<<1|1,tr[x].lz),tr[x].lz=0; }
void build(int x,int l,int r){
tr[x].lz=0;
if(l==r){
tr[x].minn=s[l-1]-us[l];
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid),build(x<<1|1,mid+1,r);
pushup(x);
}
void change(int x,int l,int r,int ml,int mr,int val){
if(ml>mr) return;
if(ml<=l&&r<=mr){
pushtag(x,val);
return;
}
pushdown(x);
int mid=(l+r)>>1;
if(ml<=mid) change(x<<1,l,mid,ml,mr,val);
if(mid+1<=mr) change(x<<1|1,mid+1,r,ml,mr,val);
pushup(x);
}
ll ask(int x,int l,int r,int ml,int mr){
if(ml>mr) return 1e18;
if(ml<=l&&r<=mr) return tr[x].minn;
pushdown(x);
int mid=(l+r)>>1;
ll ret=1e18;
if(ml<=mid) ret=min(ret,ask(x<<1,l,mid,ml,mr));
if(mid+1<=mr) ret=min(ret,ask(x<<1|1,mid+1,r,ml,mr));
return ret;
}
bool cmp(int x,int y){ return b[x]-us[x]<b[y]-us[y]; }
void work(){
scanf("%d%d%d",&n,&m,&c);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),us[i]=s[i]=0;
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
s[0]=m;
for(int i=1;i<=n;i++){
int val=min({(ll)a[i]%c,(ll)b[i],s[i-1]});
us[i]=val,s[i]=s[i-1]-val+(a[i]-val)/c;
}
ll minn=1e18;
for(int i=n;i>=1;i--){
int cnt=min({(ll)(s[i-1]-us[i])/c,(ll)(b[i]-us[i])/c,minn});
us[i]=us[i]+1ll*cnt*c;
minn=min(minn-cnt,(s[i-1]-us[i])/(c+1));
}
for(int i=1;i<=n;i++) s[i]=s[i-1]-us[i]+(a[i]-us[i])/c;
build(1,1,n);
priority_queue<int> pos;
for(int i=1;i<=n;i++) id[i]=i;
sort(id+1,id+n+1,cmp);
int tot=n;
while(tot){
int Tot=tot;
while(Tot&&b[id[Tot]]-us[id[Tot]]==b[id[tot]]-us[id[tot]]) pos.push(id[Tot]),Tot--;
int lim=b[id[Tot]]-us[id[Tot]];
while(!pos.empty()){
int x=pos.top();
int Lim=min(ask(1,1,n,x,x),ask(1,1,n,x+1,n)-1);
if(Lim<=lim) break;
int val=min(b[x]-us[x],Lim);
us[x]+=val,change(1,1,n,x,x,-val),change(1,1,n,x+1,n,-val-1);
pos.pop();
}
tot=Tot;
}
ll ans=0;
for(int i=1;i<=n;i++) ans+=a[i]-us[i];
printf("%lld\n",ans);
}
int main(){
int _;
scanf("%d",&_);
while(_--) work();
}
::::