题解:P12000 扶苏出勤日记
题外话
不知道为什么,赛时第一感觉就是 ST 表,全然忘了单调队列。但理论上 ST 表也是
思路
首先观察到答案有单调性,可以二分答案。分别枚举每一天的花钱情况。假设我们有第
代码
正解代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n,a[1000005],b[1000005],c[1000005],q[1000005];
bool check(int x){
for(int i=1;i<=n;i++)c[i]=b[i];
int jl=1,ys=0,h=0,r=-1;
for(int i=1;i<=n;i++){
while(h<=r&&a[q[r]]<=a[i])r--;
q[++r]=i;
int y=x;
if(y<=ys)ys-=y,y=0;
else y-=ys,ys=0;
while(jl<=i&&y>0){
int tmp=min((int)ceil(1.0*y/a[q[h]]),c[jl]);
y-=tmp*a[q[h]];
c[jl]-=tmp;
if(c[jl]==0){
if(q[h]==jl)h++;
jl++;
}
}
if(y>0)return 0;
ys+=-y;
}
return 1;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0),cout.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];
int l=0,r=1e12,mid,ans=0;
while(l<=r){
mid=(l+r)/2;
if(check(mid))ans=mid,l=mid+1;
else r=mid-1;
}
cout<<ans<<"\n";
}
return 0;
}
ST 表
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef int type;
inline int read(){
int x=0,f=1;
char ch=getchar_unlocked();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar_unlocked();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar_unlocked();
}
return x*f;
}
inline void write(long long x){
if(x<0)putchar_unlocked('-'),x=-x;
if(x>9)write(x / 10);
putchar_unlocked(x%10+'0');
}
int t,n,a[1000005],b[1000005],c[1000005],LOG[1000005],ST[1000005][25];
void build_log(){
LOG[0]=-1;
for(int i=1;i<=1000000;i++)LOG[i]=LOG[i/2]+1;
}
void build_st(){
for(int i=1;i<=n;i++){
ST[i][0]=a[i];
}
for(int j=1;j<=20;j++){
for(int i=1;i+(1<<j)-1<=n;i++){
ST[i][j]=max(ST[i][j-1],ST[i+(1<<j-1)][j-1]);
}
}
}
int find(int l,int r){
int w=LOG[r-l+1];
return max(ST[l][w],ST[r-(1<<w)+1][w]);
}
bool check(int x){
for(int i=1;i<=n;i++)c[i]=b[i];
int jl=1,ys=0;
for(int i=1;i<=n;i++){
int y=x;
if(y<=ys)ys-=y,y=0;
else y-=ys,ys=0;
while(jl<=i&&y>0){
int tmp=min((int)ceil(1.0*y/find(jl,i)),c[jl]);
y-=tmp*find(jl,i);
c[jl]-=tmp;
if(c[jl]==0)jl++;
}
if(y>0)return 0;
ys+=-y;
}
return 1;
}
signed main() {
build_log();
t=read();
while(t--){
n=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)b[i]=read();
build_st();
int l=0,r=1e12,mid,ans=0;
while(l<=r){
mid=(l+r)/2;
if(check(mid))ans=mid,l=mid+1;
else r=mid-1;
}
write(ans),putchar('\n');
}
return 0;
}