专栏文章
题解:P12000 扶苏出勤日记
P12000题解参与者 3已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @mipri48g
- 此快照首次捕获于
- 2025/12/03 16:45 3 个月前
- 此快照最后确认于
- 2025/12/03 16:45 3 个月前
awmc
题目大意
每天赚 块钱, 块钱可以换 个币去打乌蒙,求每天打乌蒙的最多次数。
题意分析
显然的二分,那么难点在于考虑
check。check 能想到采用模拟思路,把 天遍历一边,先赚钱,然后换币。如果中途币不够了就 return 0,能过完这 天就 return 1。考虑如何换币:假设 ,而且第 天的币足以用到第 天,那么显然在第 天换币比在第 天换币更优。
更特别的,如果 离 最近,那么它们中间的日子换币一定比这两天换币更劣,考虑到这点,使用单调栈维护。
更特别的,如果 离 最近,那么它们中间的日子换币一定比这两天换币更劣,考虑到这点,使用单调栈维护。
分类讨论,假设每天要打 把,现在是第 天,有 个币, 块钱,更优的下一天是 。
如果当前这一天是之后最优的一天,也就是说 不存在,那么把钱全部花光就好了,反正最优。
那一天存在的话,有 种情况:
第一:当前的币已经足够支撑到那一天,即
第一:当前的币已经足够支撑到那一天,即
那么一块钱都不用花。
第二:花一部分钱可以使上面的式子成立,也就是说
那么花最少的钱,因为剩下的要留给第 天。
第三:钱花完了也不能使上面的式子成立。
只能在这里把钱全部花完,因为留不到那一天,如果留给中间的日子反而劣,所以最好的是自己用完。
只能在这里把钱全部花完,因为留不到那一天,如果留给中间的日子反而劣,所以最好的是自己用完。
总的就上面几种情况,依次判断即可。
代码&细节
二分上界是 。
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int T,n;
int a[N],b[N],nxt[N];
int kkk;//第4种情况下花的钱
bool chk(int x){
int now=0,B=0;
for(int i=1;i<=n;i++){
now+=b[i];
int days=nxt[i]-i;
if(nxt[i]==-1){ //当前最优
B+=now*a[i];
now=0;
}else{
if(now*a[i]>=x*days-B){ //钱够
kkk=ceil(1.0*max(x*days-B,0ll)/a[i]); //计算最少需要花的钱
B+=kkk*a[i];
now-=kkk;
}else{ //钱不够
B+=now*a[i];
now=0;
}
}
if(B>=x)B-=x;
else return 0;
}
return 1;
}
stack<int> s;
signed main(){
ios::sync_with_stdio(0);cin.tie(0);
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
for(int i=1;i<=n;i++){ //维护单调栈
while(!s.empty()&&a[s.top()]<=a[i]){nxt[s.top()]=i;s.pop();}
s.push(i);
}
while(!s.empty())nxt[s.top()]=-1,s.pop();
int l=0,r=1e12,mid;
while(l<r){
mid=(l+r+1>>1);
if(chk(mid))l=mid;
else r=mid-1;
}
cout<<l<<'\n';
}
return 0;
}
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...